1 Introduction

This notebook contains analyses from the MEDAL study, assessing memory bias in remitted and depressed individuals. The pre-registration for the main analyses, as well as a preprint version of the accompanying article can be found here as well. The main aim of the current work was to examine how three groups (control, remitted, depressed) differ in terms of emotional memory dynamics in a real-life setting.

#Load packages 
renv::activate()
* Project 'Z:/medal_membias' loaded. [renv 0.15.5]
library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(janitor)

Attaching package: ‘janitor’

The following objects are masked from ‘package:stats’:

    chisq.test, fisher.test
library(readxl)
library(data.table)
data.table 1.14.4 using 8 threads (see ?getDTthreads).  Latest news: r-datatable.com

Attaching package: ‘data.table’

The following objects are masked from ‘package:dplyr’:

    between, first, last
library(ggplot2)
library(psych)

Attaching package: ‘psych’

The following objects are masked from ‘package:ggplot2’:

    %+%, alpha
library(devtools)
Loading required package: usethis
library(pastecs)

Attaching package: ‘pastecs’

The following objects are masked from ‘package:data.table’:

    first, last

The following objects are masked from ‘package:dplyr’:

    first, last
library(cli)
library(lmerTest) #linear mixed models 
Loading required package: lme4
Loading required package: Matrix

Attaching package: ‘lmerTest’

The following object is masked from ‘package:lme4’:

    lmer

The following object is masked from ‘package:stats’:

    step
library(performance) #fits of residuals 
library(DescTools)
Registered S3 method overwritten by 'DescTools':
  method        from       
  print.palette wesanderson

Attaching package: ‘DescTools’

The following objects are masked from ‘package:psych’:

    AUC, ICC, SD

The following object is masked from ‘package:data.table’:

    %like%
library(tidyr) # Separate trigger column

Attaching package: ‘tidyr’

The following objects are masked from ‘package:Matrix’:

    expand, pack, unpack

The following object is masked from ‘package:pastecs’:

    extract
library(sjPlot) # for nice tables and interaction plots 
Install package "strengejacke" from GitHub (`devtools::install_github("strengejacke/strengejacke")`) to load all sj-packages at once!
library(knitr) # to print the tables within notebook
library(foreach) #run parallel loops

Attaching package: ‘foreach’

The following object is masked from ‘package:DescTools’:

    %:%
library(parallel)
library(doParallel) #run parallel loops
Loading required package: iterators
library(ggpubr) # emmeans
library(mediation) #mediation analysis 
Loading required package: MASS

Attaching package: ‘MASS’

The following object is masked from ‘package:dplyr’:

    select

Loading required package: mvtnorm
Loading required package: sandwich
mediation: Causal Mediation Analysis
Version: 4.5.0


Attaching package: ‘mediation’

The following object is masked from ‘package:psych’:

    mediate
library(plotly) #for interactive plots

Attaching package: ‘plotly’

The following object is masked from ‘package:MASS’:

    select

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout
library(jtools) #for theme_apa

Attaching package: ‘jtools’

The following object is masked from ‘package:DescTools’:

    %nin%
library(JSmediation) #moderated mediation
library(wesanderson) 
source("functions.R")

2 Data

Here we load in our data and preprocess it in steps. We first need to separate the different surveys that were delivered to bring them into the same sampling times, merge in some descriptives we need as covariates, and estimate subject-centered and lagged variables for our models later.

  1. Load and clean data
# Load the data
MEDAL_ESM_compleet <- read_excel("data/MEDAL_ESM_compleet.xlsx")
# Move variables around and clean names
MEDAL_ESM_compleet= MEDAL_ESM_compleet %>%
  rename(id='Movisens-ID') %>% 
  clean_names() %>%
  rename(subjectcode = 'deelnemersnr') %>% 
  relocate('subjectcode', .after = 'id')
df_medal_try = MEDAL_ESM_compleet
  1. Split different EMA surveys we have
# Sleep EMA Qs
df_medal_sleep = df_medal_try %>% 
  filter(form=='Slaap') %>% 
  dplyr::select(c(1, 2, 4, 5, 7, 9, 14)) 
# Recent EMA Qs
df_medal_recent = df_medal_try %>% 
  filter(form=='Recent') %>% 
  dplyr::select(c(1, 2, 4, 5, 7, 9, contains('rec')))
# Remote EMA Qs
df_medal_remote = df_medal_try %>%
  filter(form=='Remote') %>%
  dplyr::select(c(1, 2, 4, 5, 7, 9, contains('rem')))
# Mastery EMA Qs
df_medal_mastery = df_medal_try %>%
  filter(form=='Mastery') %>% 
  dplyr::select(c(1, 2, 4, 5, 7, 9, contains('master')))
# Standard Qs
df_medal_standard = df_medal_try %>%
  filter(form=='Standaard')  %>%
  dplyr::select(c(1, 2, 4, 5, 7, 9, (-contains('mastery') & -contains('rem') & -contains('rec')))) %>% 
  dplyr::select(-c(7,13,14))

# merge sleep and standard
df_medal_merged = merge(df_medal_sleep, df_medal_standard, by=c('id', 'trigger_counter', 'subjectcode'), suffixes = c("_sleep", ""), all=T )

# merge to recent, remote and mastery
df_medal_merged= merge(df_medal_merged, df_medal_recent, by=c('id', 'trigger_counter', 'subjectcode' ), suffixes = c('', '_recent'), all = T )
df_medal_merged = merge(df_medal_merged, df_medal_remote, by=c('id', 'trigger_counter', 'subjectcode' ), suffixes = c('', '_remote'), all = T )
df_medal_merged = merge(df_medal_merged, df_medal_mastery, by=c('id', 'trigger_counter', 'subjectcode' ), suffixes = c('', '_mastery'), all = T )

# Fix start dates and times
df_medal_merged$form_start_date <- as.character(df_medal_merged$form_start_date)
df_medal_merged$form_start_date <- as.ITime(df_medal_merged$form_start_date)
df_medal_merged = df_medal_merged %>% 
  dplyr::mutate(form_start_date = ifelse(is.na(form_start_date), form_start_date_sleep, form_start_date))
  1. Add variables on Education, Gender, and Age
# Load in previous data for demographics (also contains EMA)
load("data/IPAQ_Maeve_Workspace.RData")
df_MEDAL <- df_MEDAL[-c(192), ]

# Select relevant demo info
df_MEDAL = df_MEDAL %>% 
  dplyr::select(1, 3, 5:7) %>% 
  rename('subjectcode' = 'subject', 'education' = 'Education3groups', 'n_episodes'='NumberEpisodes' )

# merge demo to full EMA
df_medal_merged =  merge(df_medal_merged, df_MEDAL, by = c('subjectcode'), all = T ) %>%
  clean_names() 

df_medal_merged$education = as.factor(df_medal_merged$education)
df_medal_merged$gender = as.factor(df_medal_merged$gender)

df_medal_merged = df_medal_merged %>% 
  relocate(c('id', 'gender', 'age', 'education'), .after = 'subjectcode') %>% 
  relocate ('age', .after = 'gender') %>% 
  relocate ('education', .after = 'age') %>% 
  relocate ('id', .before = 'subjectcode')
  1. Categorize the subjectcode into the three conditions (Depressed, Remitted, Control (Never-depressed))
df_medal_merged$condition = case_when(df_medal_merged$subjectcode >= 700 & df_medal_merged$subjectcode < 800 ~ "remitted",
                                      df_medal_merged$subjectcode >= 800 & df_medal_merged$subjectcode < 900 ~ "depressed", 
                                      df_medal_merged$subjectcode >= 900 ~ "control")
df_medal_merged = df_medal_merged %>% relocate ('condition', .after = 'subjectcode' )
df_medal_merged$condition <- as.factor(df_medal_merged$condition)
  1. Calculate reaction time
df_medal_merged$rt_sleep = lubridate::as.difftime( df_medal_merged$form_finish_date_sleep - df_medal_merged$form_start_date_sleep)
  1. Separate time from when trigger was sent

df_medal_merged = df_medal_merged %>% 
  tidyr::separate(trigger, c('Random', 'Time', 'Trigger_Time_1', 'Trigger_Time_2'))  %>% 
  dplyr::mutate(trigger_time = paste(Trigger_Time_1, Trigger_Time_2, sep=':')) %>%#separate time from previous trigger
  dplyr::mutate(trigger = paste(Random, Time, trigger_time, sep=' ')) #bring back 'trigger' column 

#Turn numbers into time format
df_medal_merged$trigger_time <- as.ITime(df_medal_merged$trigger_time)
  1. Find the trigger number per day
#df_medal_merged$trigger_counter[is.na(df_medal_merged$trigger_time)] <- 1

df_medal_merged$trigger_number[is.na(df_medal_merged$trigger_time)] <- 1 
df_medal_merged$trigger_number[df_medal_merged$trigger_time >= (as.ITime("10:00:00"))& df_medal_merged$trigger_time < (as.ITime("12:00:00"))] <- 2
df_medal_merged$trigger_number[df_medal_merged$trigger_time >= (as.ITime("12:00:00"))& df_medal_merged$trigger_time < (as.ITime("14:00:00"))] <- 3
df_medal_merged$trigger_number[df_medal_merged$trigger_time >= (as.ITime("14:00:00"))& df_medal_merged$trigger_time < (as.ITime("16:00:00"))] <- 4
df_medal_merged$trigger_number[df_medal_merged$trigger_time >= (as.ITime("16:00:00"))& df_medal_merged$trigger_time < (as.ITime("18:00:00"))] <- 5
df_medal_merged$trigger_number[df_medal_merged$trigger_time >= (as.ITime("18:00:00"))& df_medal_merged$trigger_time < (as.ITime("20:00:00"))] <- 6
df_medal_merged$trigger_number[df_medal_merged$trigger_time >= (as.ITime("20:00:00"))& df_medal_merged$trigger_time < (as.ITime("23:00:01"))] <- 7

# df
df_medal_merged = df_medal_merged %>% 
  relocate ('trigger_number', .after = 'trigger_counter')%>% relocate('trigger_time', .before ='form_start_date') %>%
  relocate('trigger', .before ='trigger_time')
  1. Final cleaning of the dataset

#Create dataset where double morning list is removed 
df_medal_merged = df_medal_merged %>% 
  dplyr::mutate(trigger_counter=ifelse(trigger_number==1 & lag(trigger_number)==1, lag(trigger_counter), trigger_counter)) %>% 
  dplyr::mutate(trigger_counter=ifelse(trigger_number==1 & lag(trigger_number)==1, lag(trigger_counter), trigger_counter)) %>%
  dplyr::mutate(trigger_counter=ifelse(trigger_number==1 & lag(trigger_number)==1, lag(trigger_counter), trigger_counter)) %>%
  dplyr::mutate(trigger_counter=ifelse(trigger_number==1 & lag(trigger_number)==1, lag(trigger_counter), trigger_counter)) %>% 
  dplyr::mutate(trigger_counter=ifelse(trigger_number==1 & lag(trigger_number)==1, lag(trigger_counter), trigger_counter))

# now we have the clean dataframe, remove duplicated coloumns
df_medal_clean = df_medal_merged %>%
  dplyr::group_by(subjectcode) %>% 
  distinct(trigger_counter, .keep_all = TRUE) %>% 
  dplyr::select (1:12, 17:60) %>% 
  dplyr::mutate(original_order = row_number()) %>% 
  relocate('original_order', .before = 'id')

#Set the order of the factor to control, remission, depression (for visual purposes)
df_medal_clean$condition <- factor(df_medal_clean$condition, levels=c('control', 'remitted', 'depressed' ), labels=c('control', 'remitted', 'depressed'))

# Create dummy variable 
df_medal_clean = df_medal_clean %>% 
  mutate(condition_dummy = case_when(condition == 'depressed'~ 3, condition == 'remitted'~ 2, condition == 'control' ~ 1))

df_medal_clean$condition_dummy = as.factor(df_medal_clean$condition_dummy)

#set weekday 
df_medal_clean$form_finish_date <- as.character(df_medal_clean$form_finish_date)
df_medal_clean$form_finish_date <- strptime(df_medal_clean$form_finish_date, format = '%Y-%m-%d %H:%M:%S')

df_medal_clean$finish_date <- as.Date(df_medal_clean$form_finish_date)
df_medal_clean$weekday <- as.integer(format(df_medal_clean$finish_date, '%w'))
df_medal_clean = df_medal_clean %>% relocate('weekday', .after = 'trigger_number')

#solve duplicate issue 
df_medal_duplicate = df_medal_clean %>% dplyr::group_by(subjectcode, weekday) %>% filter(duplicated(trigger_number))

  #since row 10 for subject 712 is a duplicate morning list
  df_medal_clean <- subset(df_medal_clean, !(subjectcode == 712 & original_order == 10))
  df_medal_clean = df_medal_clean %>% dplyr::group_by(subjectcode, weekday) %>% 
    mutate(temp = lead(trigger_number), 
           trigger_number = case_when(trigger_number == temp ~ (temp -1), TRUE ~ trigger_number)) %>%
    select(-temp)
  #Take the rows out that have 'NA'for the weekday since form wasn't finished and there is no data for PA, NA, or Memory
  df_medal_clean = df_medal_clean %>% filter(!is.na(weekday))
  df_medal_clean$original_order <- 1:nrow(df_medal_clean) 

# Create expanded df with all potential datapoints

df_medal_day = df_medal_clean %>% 
  dplyr::select('subjectcode', 'weekday', 'original_order') %>% 
  dplyr::mutate(weekday = as.numeric(weekday)) %>%
  dplyr::group_by(subjectcode) %>%
  dplyr:: distinct(weekday, .keep_all =T) %>% 
  dplyr::ungroup()

df_medal_day = df_medal_day %>% 
  slice(rep(1:n(), each = 7)) %>% 
  dplyr::mutate(trigger_number = rep(1:7, length.out=n())) %>% 
  dplyr::rename(order = original_order)


#merge with main dataframe
df_medal_clean =  merge(df_medal_day, df_medal_clean, by=c('subjectcode', 'trigger_number', 'weekday'), all= T) 
df_medal_clean = df_medal_clean %>% mutate(order = as.numeric(order))
df_medal_clean = arrange(df_medal_clean, order)
  1. Centre, scale, and average Variables

used_vars = c("neg_mood", "rec_mem_neg_mood", "rem_mem_neg_mood", "pos_mood", "rec_mem_pos_mood", "rem_mem_pos_mood")

#Centering & scaling 
df_medal_clean = df_medal_clean %>% 
  dplyr::group_by(subjectcode) %>%
  # Center and scale
  dplyr::mutate( across(used_vars, ~ (.x/10), .names = "{.col}" ),
                 across(used_vars, ~ mean(.x, na.rm=T), .names = "{.col}_m" ),
                 across(used_vars, ~ (.x - mean(.x, na.rm=T)), .names = "{.col}_c" ), 
                 across(paste0(used_vars, "_c"), ~ DescTools::Winsorize(.x, na.rm = T), .names = "{.col}")) %>%  
  ungroup() %>%
  # Rescale to positive
  mutate(across(c(paste0(used_vars,"_c")), ~ abs(min(.x, na.rm = T)) + 1 + .x, .names = "{.col}s"))
  1. Lag variables
# Remote 

df_medal_clean = df_medal_clean %>%
  dplyr::group_by(subjectcode) %>%
  mutate(rem_mem_pos_mood_lag = lead(rem_mem_pos_mood, n=7, order_by=subjectcode),
         rem_mem_neg_mood_lag = lead(rem_mem_neg_mood, n=7, order_by=subjectcode),
         pos_mood_lag_rem = lead(pos_mood, n=7, order_by=subjectcode),
         neg_mood_lag_rem = lead(neg_mood, n=7, order_by=subjectcode), 
         rem_mem_pos_mood_cs_lag = lead(rem_mem_pos_mood_cs, n=7, order_by=subjectcode),
         rem_mem_neg_mood_cs_lag = lead(rem_mem_neg_mood_cs, n=7, order_by=subjectcode),
         pos_mood_cs_lag_rem = lead(pos_mood_cs, n=7, order_by=subjectcode),
         neg_mood_cs_lag_rem = lead(neg_mood_cs, n=7, order_by=subjectcode),
         rem_mem_pos_mood_c_lag = lead(rem_mem_pos_mood_c, n=7, order_by=subjectcode),
         rem_mem_neg_mood_c_lag = lead(rem_mem_neg_mood_c, n=7, order_by=subjectcode),
         pos_mood_c_lag_rem = lead(pos_mood_c, n=7, order_by=subjectcode),
         neg_mood_c_lag_rem = lead(neg_mood_c, n=7, order_by=subjectcode)) %>% 
  filter(!is.na(original_order)) # filter out the NA rows for the lagging of recent memory 

# Recent
df_medal_clean = df_medal_clean %>% 
  dplyr::group_by(subjectcode) %>%
  mutate(rec_mem_pos_mood_lag = lead(rec_mem_pos_mood, n=1, order_by=subjectcode),
         rec_mem_neg_mood_lag = lead(rec_mem_neg_mood, n=1, order_by=subjectcode),
         pos_mood_lag_rec = lead(pos_mood, n=1, order_by=subjectcode),
         neg_mood_lag_rec = lead(neg_mood, n=1, order_by=subjectcode),
         rec_mem_pos_mood_cs_lag = lead(rec_mem_pos_mood_cs, n=1, order_by=subjectcode),
         rec_mem_neg_mood_cs_lag = lead(rec_mem_neg_mood_cs, n=1, order_by=subjectcode),
         pos_mood_cs_lag_rec = lead(pos_mood_cs, n=1, order_by=subjectcode),
         neg_mood_cs_lag_rec = lead(neg_mood_cs, n=1, order_by=subjectcode),
         rec_mem_pos_mood_c_lag = lead(rec_mem_pos_mood_c, n=1, order_by=subjectcode),
         rec_mem_neg_mood_c_lag = lead(rec_mem_neg_mood_c, n=1, order_by=subjectcode),
         pos_mood_c_lag_rec = lead(pos_mood_c, n=1, order_by=subjectcode),
         neg_mood_c_lag_rec = lead(neg_mood_c, n=1, order_by=subjectcode)) %>% 
  ungroup()
  

Descriptives

We first plot some general population descriptives, followed by some descriptives of the scales we use in the EMA weeks and compliance rates for both positive and negative mood.

Population

Demographics

#Create Descriptives Tables
summary_table = df_medal_clean %>% distinct(subjectcode, .keep_all = TRUE) %>% group_by(condition) %>% summarise(
  'N' = n(),
  'Age \n M +/- SD' = paste0(round(mean(age, na.rm =T), 1), ' +/- ' , round(sd(age, na.rm =T), 1)),
  #'NA Age' = sum(is.na(age)), 
  '% Education Low' = mean(education == 0, na.rm = T)*100,
  '% Education Middle' = mean(education == 1, na.rm = T)*100,
  '% Education High' = mean(education == 2, na.rm = T)*100,
  #'NA Education' = sum(is.na(education)), 
  '% Female' = mean(gender ==1, na.rm = T)*100,
  #'NA Gender' = sum(is.na(gender))
)

#Compliance rates
df_medal_compliance_individual = df_medal_clean %>% group_by(condition, subjectcode) %>% summarise('ComplianceRate' = sum(!is.na(trigger_number))/42*100)
`summarise()` has grouped output by 'condition'. You can override using the `.groups` argument.
length(which(df_medal_compliance_individual$ComplianceRate <70))
[1] 8
df_medal_compliance = df_medal_clean %>% group_by(condition) %>% summarise('% Mean Compliance' = sum(!is.na(trigger_number))/(n_distinct(subjectcode) *42)*100) 


# Create a table
summary_table = summary_table %>% left_join(df_medal_compliance, by = 'condition')
rempsyc::nice_table(summary_table)

condition

N

Age
M +/- SD

% Education Low

% Education Middle

% Education High

% Female

% Mean Compliance

control

55

51.7 +/- 10.9

0.00

22.64

77.36

78.18

92.42

remitted

90

52.5 +/- 11.1

3.49

16.28

80.23

78.41

91.88

depressed

46

48.7 +/- 11.2

4.35

30.43

65.22

71.74

92.65

Tests

#create dataset with only unique subjectcode 
df_medal_distinct = df_medal_clean %>% distinct(subjectcode, .keep_all = TRUE)%>% select('subjectcode', 'condition', 'age', 'education', 'gender')

#Test for differences between groups 
  #Age
  df_medal_distinct %>% lm(age ~ condition, data=.) %>% summary()

Call:
lm(formula = age ~ condition, data = .)

Residuals:
    Min      1Q  Median      3Q     Max 
-26.717  -6.511   2.489   7.489  18.283 

Coefficients:
                   Estimate Std. Error t value Pr(>|t|)    
(Intercept)         51.6727     1.4876  34.736   <2e-16 ***
conditionremitted    0.8386     1.8963   0.442    0.659    
conditiondepressed  -2.9553     2.2042  -1.341    0.182    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 11.03 on 186 degrees of freedom
  (2 observations deleted due to missingness)
Multiple R-squared:  0.0192,    Adjusted R-squared:  0.008657 
F-statistic: 1.821 on 2 and 186 DF,  p-value: 0.1648
  
  #education
  chisq.test(df_medal_distinct$education, df_medal_distinct$condition)
Warning in stats::chisq.test(x, y, ...) :
  Chi-squared approximation may be incorrect

    Pearson's Chi-squared test

data:  df_medal_distinct$education and df_medal_distinct$condition
X-squared = 5.8234, df = 4, p-value = 0.2127
  
  #gender
  chisq.test(df_medal_distinct$gender, df_medal_distinct$condition)

    Pearson's Chi-squared test

data:  df_medal_distinct$gender and df_medal_distinct$condition
X-squared = 0.84533, df = 2, p-value = 0.6553

Plot

#Create a Graph  
  #age
  boxplot_age <- ggplot(df_medal_distinct, aes(x=condition, y=age, fill=condition)) +
    geom_boxplot() +
    labs(x = 'Condition', y = 'Age', tag = 'C' ) +
    ggtitle('Age per Condition') +
    scale_fill_manual(values = wesanderson::wes_palette(n=3, name='GrandBudapest2' ))  +
    theme_apa() 
  ggplotly(boxplot_age)
Warning: Removed 2 rows containing non-finite values (`stat_boxplot()`).
    
    #education
    plot_educ <- ggplot(df_medal_distinct, aes(x=condition, fill = education)) +
      geom_bar(position = 'dodge') +
      labs(x='Condition', y= 'Proportion', tag = 'A' ) +
      ggtitle('Education Level per Condition') +
      scale_fill_manual(values = wesanderson::wes_palette(n=3, name='GrandBudapest2' ), labels = c('Low' , 'Middle' , 'High'), name = 'Education')  +
      theme_apa() 
    ggplotly(plot_educ)
      
    #Gender
    plot_gender <- ggplot(df_medal_distinct, aes(x=condition, fill = gender)) +
      geom_bar(position = 'dodge') +
      labs(x = 'Condition', y = 'Proportion', tag = 'B' ) +
      ggtitle('Gender per Condition') +
      scale_fill_manual(values = wesanderson::wes_palette(n=3, name='GrandBudapest2' ), labels = c('Male', 'Female'), 'Gender')  +
      theme_apa() 
    ggplotly(plot_gender)

Positive Mood

Current Mood

describe.by(df_medal_clean$pos_mood, group=df_medal_clean$condition) %>% rbindlist() %>% mutate(vars=c("cont", "rem", "dep"))

Distribution

ggplot(data= df_medal_clean, aes(x=pos_mood)) + geom_histogram()+facet_grid(cols=vars(condition))

Centred Distribution

ggplot(data= df_medal_clean, aes(x=pos_mood_c)) + geom_histogram()+facet_grid(cols=vars(condition))

Recent Memory

describe.by(df_medal_clean$rec_mem_pos_mood, group=df_medal_clean$condition) %>% rbindlist() %>% mutate(vars=c("cont", "rem", "dep"))

Distribution

ggplot(data= df_medal_clean, aes(x=rec_mem_pos_mood)) + geom_histogram()+facet_grid(cols=vars(condition))

Centred Distribution

ggplot(data= df_medal_clean, aes(x=rec_mem_pos_mood_c)) + geom_histogram()+facet_grid(cols=vars(condition))

Remote Memory

describe.by(df_medal_clean$rem_mem_pos_mood, group=df_medal_clean$condition) %>% rbindlist() %>% mutate(vars=c("cont", "rem", "dep"))

Distribution

ggplot(data= df_medal_clean, aes(x=rem_mem_pos_mood)) + geom_histogram()+facet_grid(cols=vars(condition))

Centred Distribution

ggplot(data= df_medal_clean, aes(x=rem_mem_pos_mood_c)) + geom_histogram()+facet_grid(cols=vars(condition))

Negative Mood

Current Mood

describe.by(df_medal_clean$neg_mood, group=df_medal_clean$condition)%>% rbindlist() %>% mutate(vars=c("cont", "rem", "dep"))

Distribution

ggplot(data= df_medal_clean, aes(x=neg_mood)) + geom_histogram()+facet_grid(cols=vars(condition))

Centred Distribution

ggplot(data= df_medal_clean, aes(x=neg_mood_c)) + geom_histogram()+facet_grid(cols=vars(condition))
ggplot(data= df_medal_clean, aes(x=neg_mood_cs)) + geom_histogram()+facet_grid(cols=vars(condition))

Recent Memory

describe.by(df_medal_clean$rec_mem_neg_mood, group=df_medal_clean$condition) %>% rbindlist() %>% mutate(vars=c("cont", "rem", "dep"))

Distribution

ggplot(data= df_medal_clean, aes(x=rec_mem_neg_mood)) + geom_histogram()+facet_grid(cols=vars(condition))

Centred Distribution

ggplot(data= df_medal_clean, aes(x=rec_mem_neg_mood_c)) + geom_histogram()+facet_grid(cols=vars(condition))

Remote Memory

describe.by(df_medal_clean$rem_mem_neg_mood, group=df_medal_clean$condition) %>% rbindlist() %>% mutate(vars=c("cont", "rem", "dep"))

Distribution

ggplot(data= df_medal_clean, aes(x=rem_mem_neg_mood)) + geom_histogram()+facet_grid(cols=vars(condition))

Centred Distribution

ggplot(data= df_medal_clean, aes(x=rem_mem_neg_mood_c)) + geom_histogram()+facet_grid(cols=vars(condition))

3 Main Effects

A simple linear regression analysis was done to look at the differences in positive and negative mood ratings per condition.

3.1 Linear Mixed Models for PA and NA

#positive mood 
positive_model = lmer(pos_mood ~ condition + (1|subjectcode), data = df_medal_clean)


#negative mood
negative_model = lmer(neg_mood ~ condition + (1|subjectcode), data = df_medal_clean)



asis_output(tab_model (positive_model, negative_model, 
                      show.se = T, show.df = T, show.aic = T, transform = NULL,  
                      show.stat = T, show.std = T, 
                      title = 'Condition Differences Mood Rating', dv.labels = c('PA Scaled',  'NA Scaled') )$knitr)

Plot


#create boxplot for negative and positive affect for each group with significance levels 
combine_data = df_medal_clean %>%
  tidyr::pivot_longer(cols=c(pos_mood, neg_mood), names_to = 'mood_type', values_to = 'mood_rating') %>% 
  dplyr::mutate(mood_type = factor(mood_type, levels = c('pos_mood' , 'neg_mood')))

# Plot
lm_plot = ggplot(combine_data, aes(x=condition, y = mood_rating, fill= condition)) + 
  geom_boxplot() +
  labs(x ='Group', y ='Mood (scaled units)' ) +
  scale_x_discrete(labels = c('control' = 'Never Depressed', 'remitted' = 'Remitted', 'depressed' = 'Depressed' )) +
  facet_wrap( ~ mood_type, ncol =3, nrow = 2, labeller  = labeller(mood_type = c('pos_mood' = 'Positive Mood', 'neg_mood'  = 'Negative Mood'))) +
  geom_signif(comparisons = list(c('control', 'remitted'), c('control' , 'depressed'), c('remitted' , 'depressed' )), map_signif_level = T, y_position = c(15, 13, 11)) +
  scale_fill_manual(values = wesanderson::wes_palette(n=3, name='GrandBudapest2' ))  +
  theme_apa() + 
  guides(fill=F)
ggplotly(lm_plot)
ggsave('figure_1_main_effects.pdf', dpi = 320, width = 12, height = 8, path = "figures/")

Follow-Up

emmeans::emmeans(positive_model, pairwise ~ condition, pbkrtest.limit = 7800, lmerTest.limit=7800)
emmeans::emmeans(negative_model, pairwise ~ condition, pbkrtest.limit = 7800, lmerTest.limit=7800)

4 Hypothesis 1: Independent Models

In this section we test the first models from hypothesis 1 as stated in the pre-registraiton. These analyses look at the relationship between recent and remote emotional memory for both positive and negative affect, while also looking at group differences in these relaitonships based on depression status.

# set model families
model_families = c('gauss-link', "gauss-log", 'gauss-inv', 'Gamma-link', 'Gamma-log')
# detect cores for later
ncores = detectCores()-1

Positive Affect

First we run the positive affect models. For each of the recent and remote models, we check the best fitting model as stated in the pre-registration based on the AIC and the residuals. We then check whether mediation analyses are warranted, and run those. Within each tab below, we present the results and steps taken, as well as post-hoc analyses to examine the directionality of the effects.

Recent

# Model equation
h1_post_recent_eq = "pos_mood_cs ~ 1 + condition*rec_mem_pos_mood_cs_lag + gender + age + education + (1 + rec_mem_pos_mood_cs_lag|subjectcode)"

# set clusters
cl = makeCluster(ncores)
registerDoParallel(cl)

# run parallel
h1_pos_recent_models = foreach(family = model_families, .combine = 'c', .packages = c('lmerTest'), .errorhandling = "remove") %dopar% {
  fit_all_mods(h1_post_recent_eq, df_medal_clean, family) }
stopCluster(cl)

# print the models into a single table
asis_output( tab_model(h1_pos_recent_models,  dv.labels = names(h1_pos_recent_models), 
                       show.icc = T, show.aic = T, transform = NULL, show.se = T, digits = 3)$knitr)
summary(h1_pos_recent_models[[2]])
plot_diagnostics(h1_pos_recent_models)
car::vif(h1_pos_recent_models[[2]]) #Vifs were inspected without interaction and deemed OK
Follow-up

In the follow-up we look at the pairwise differences in the slopes, and the indiivuds

emmeans::emtrends(h1_pos_recent_models[[2]], pairwise ~ condition, var='rec_mem_pos_mood_cs_lag', lmerTest.limit = 3500, pbkrtest.limit = 3500 )
#create separate dataframes 
df_medal_clean_control = df_medal_clean %>% filter(condition == 'control')
df_medal_clean_remitted = df_medal_clean %>% filter(condition == 'remitted')
df_medal_clean_depressed = df_medal_clean %>% filter(condition == 'depressed') 


m1_pos_rec_control <-   lmer(pos_mood_cs ~ rec_mem_pos_mood_cs_lag + gender + age + education 
                     + (1  +  rec_mem_pos_mood_cs_lag|subjectcode), 
                   data=df_medal_clean_control,
                   control = lmerControl(calc.derivs = F, optimizer='bobyqa', optCtrl=list(maxfun=1e6)))

m1_pos_rec_remitted <-   lmer(pos_mood_cs ~ rec_mem_pos_mood_cs_lag + gender + age + education 
                     + (1 + rec_mem_pos_mood_cs_lag|subjectcode), 
                   data=df_medal_clean_remitted,
                   control = lmerControl(calc.derivs = F, optimizer='bobyqa', optCtrl=list(maxfun=1e6)))

m1_pos_rec_depressed <-   lmer(pos_mood_cs ~ rec_mem_pos_mood_cs_lag + gender + age + education 
                     + (1  + rec_mem_pos_mood_cs_lag|subjectcode), 
                   data=df_medal_clean_depressed,
                   control = lmerControl(calc.derivs = F, optimizer='bobyqa', optCtrl=list(maxfun=1e6)))

asis_output(tab_model(m1_pos_rec_control, m1_pos_rec_remitted, m1_pos_rec_depressed, show.se = T, show.aic = T, transform = NULL, dv.labels = c('control', 'remitted', 'depressed'))$knitr) 

Remote

# Model equation
h1_pos_remote_eq = "pos_mood_cs ~ 1 +  condition*rem_mem_pos_mood_cs_lag + gender + age + education + (1  + rem_mem_pos_mood_cs_lag|subjectcode)"

# set clusters
cl = makeCluster(ncores)
registerDoParallel(cl)

# run parallel
h1_pos_remote_models = foreach(family = model_families, .combine = 'c', .packages = c('lmerTest'),  .errorhandling = "remove") %dopar% {
  fit_all_mods(h1_pos_remote_eq, df_medal_clean, family) }
stopCluster(cl)

# print the models into a single table
asis_output( tab_model(h1_pos_remote_models, dv.labels = names(h1_pos_remote_models), 
                       show.icc = T, show.aic = T, transform = NULL, show.se = T, digits = 3)$knitr)
summary(h1_pos_remote_models[[2]])
plot_diagnostics(h1_pos_remote_models)
car::vif(h1_pos_remote_models[[2]]) #VIFs without interactions were fine
Follow-up
emmeans::emtrends(h1_pos_remote_models[[4]], pairwise ~ condition, var='rem_mem_pos_mood_cs_lag' )

m1_pos_rem_control <- lmer(pos_mood_cs ~ 1 + rem_mem_pos_mood_cs_lag + gender + age + education + (1  + rem_mem_pos_mood_cs_lag|subjectcode), 
                     data=df_medal_clean_control,
                    control = lmerControl(calc.derivs = F, optimizer='bobyqa', optCtrl=list(maxfun=1e6)))

m1_pos_rem_remitted <- lmer(pos_mood_cs ~ 1 + rem_mem_pos_mood_cs_lag + gender + age + education + (1  + rem_mem_pos_mood_cs_lag|subjectcode), 
                     data=df_medal_clean_remitted,
                     control = lmerControl(calc.derivs = F, optimizer='bobyqa', optCtrl=list(maxfun=1e6)))

m1_pos_rem_depressed <- lmer(pos_mood_cs ~ 1 + rem_mem_pos_mood_cs_lag + gender + age + education + (1  + rem_mem_pos_mood_cs_lag|subjectcode), 
                       data=df_medal_clean_depressed,
                       control = lmerControl(calc.derivs = F, optimizer='bobyqa', optCtrl=list(maxfun=1e6)))

asis_output(tab_model(m1_pos_rem_control, m1_pos_rem_remitted, m1_pos_rem_depressed, show.se = T, show.aic = T, transform = NULL, dv.labels = c('control', 'remitted', 'depressed'))$knitr) 

Negative Affect

We next run the negative affect models. For each of the recent and remote models, we check the best fitting model as stated in the pre-registration based on the AIC and the residuals. We then check whether mediation analyses are warranted, and run those. Within each tab below, we present the results and steps taken, as well as post-hoc analyses to examine the directionality of the effects

Recent

# Model equation
h1_neg_recent_eq = "neg_mood_cs ~ condition*rec_mem_neg_mood_cs_lag  + gender + age + education + (1 + rec_mem_neg_mood_cs_lag | subjectcode)"
# set clusters
cl = makeCluster(ncores)
registerDoParallel(cl)

# run parallel
h1_neg_recent_models = foreach(family = model_families, .combine = 'c', .packages = c('lmerTest'), .errorhandling = 'remove') %dopar% {
  fit_all_mods(h1_neg_recent_eq, df_medal_clean, family) }
stopCluster(cl)

# print the models into a single table
asis_output( tab_model(h1_neg_recent_models,  dv.labels = names(h1_neg_recent_models), 
                       show.icc = T, show.aic = T, transform = NULL, show.se = T, digits = 3)$knitr)
summary(h1_neg_recent_models[[4]])
plot_diagnostics(h1_neg_recent_models)
car::vif(h1_neg_recent_models[[4]])

Follow-up

emmeans::emtrends(h1_neg_recent_models[[4]], pairwise ~ condition, var='rec_mem_neg_mood_cs_lag' )

emmeans::emmeans(h1_neg_recent_models[[4]], identity ~ rec_mem_neg_mood_cs_lag | condition )

m1_neg_rec_control <- glmer(neg_mood_cs ~ 1 + rec_mem_neg_mood_cs_lag + gender + age + education + (0  + rec_mem_neg_mood_cs_lag|subjectcode), 
                   data=df_medal_clean_control,
                   family = Gamma(link=identity),
                   control = glmerControl(calc.derivs = F, optimizer='bobyqa', optCtrl=list(maxfun=1e6)))

m1_neg_rec_remitted <-glmer(neg_mood_cs ~ 1 + rec_mem_neg_mood_cs_lag + gender + age + education + (0  + rec_mem_neg_mood_cs_lag|subjectcode), 
                   data=df_medal_clean_remitted,
                   family = Gamma(link=identity),
                   control = glmerControl(calc.derivs = F, optimizer='bobyqa', optCtrl=list(maxfun=1e6)))

m1_neg_rec_depressed <-glmer(neg_mood_cs ~ 1 + rec_mem_neg_mood_cs_lag + gender + age + education + (0  + rec_mem_neg_mood_cs_lag|subjectcode), 
                   data=df_medal_clean_depressed,
                   family = Gamma(link=identity),
                   control = glmerControl(calc.derivs = F, optimizer='bobyqa', optCtrl=list(maxfun=1e6)))

asis_output(tab_model(m1_neg_rec_control, m1_neg_rec_remitted, m1_neg_rec_depressed, show.se = T, show.aic = T, transform = NULL, dv.labels = c('control', 'remitted', 'depressed'))$knitr) 

Remote

# Model equation
h1_neg_remote_eq = "neg_mood_cs ~ condition*rem_mem_neg_mood_cs_lag  + gender + age + education + (0  + rem_mem_neg_mood_cs_lag|subjectcode)"

# set clusters
cl = makeCluster(ncores)
registerDoParallel(cl)

# run parallel
h1_neg_remote_models = foreach(family = model_families, .combine = 'c', .packages = c('lmerTest'),  .errorhandling = "remove") %dopar% {
  fit_all_mods(h1_neg_remote_eq, df_medal_clean, family) }
stopCluster(cl)

# print the models into a single table
asis_output( tab_model(h1_neg_remote_models,   dv.labels = names(h1_neg_remote_models), 
                       show.icc = T, show.aic = T, transform = NULL, show.se = T, digits = 3)$knitr)
summary(h1_neg_remote_models[[2]])
plot_diagnostics(h1_neg_remote_models)
car::vif(h1_neg_remote_models[[2]])

Follow-up

emmeans::emtrends(h1_neg_remote_models[[2]], pairwise ~ condition, var='rem_mem_neg_mood_cs_lag' )

m1_neg_rem_control <-  glmer(neg_mood_cs ~ 1 + rem_mem_neg_mood_cs_lag + gender + age + education + (0  + rem_mem_neg_mood_cs_lag|subjectcode), 
                   data=df_medal_clean_control,
                   family = Gamma(link=identity),
                   control = glmerControl(calc.derivs = F, optimizer='bobyqa', optCtrl=list(maxfun=1e6)))

m1_neg_rem_remitted <- glmer(neg_mood_cs ~ 1 + rem_mem_neg_mood_cs_lag + gender + age + education + (0  + rem_mem_neg_mood_cs_lag|subjectcode),
                   data=df_medal_clean_remitted,
                   family = Gamma(link=identity),
                   control = glmerControl(calc.derivs = F, optimizer='bobyqa', optCtrl=list(maxfun=1e6)))

m1_neg_rem_depressed <-  glmer(neg_mood_cs ~ 1 + rem_mem_neg_mood_cs_lag + gender + age + education + (0  + rem_mem_neg_mood_cs_lag|subjectcode),
                   data=df_medal_clean_depressed,
                   family = Gamma(link=identity),
                   control = glmerControl(calc.derivs = F, optimizer='bobyqa', optCtrl=list(maxfun=1e6)))

asis_output(tab_model(m1_neg_rem_control, m1_neg_rem_remitted, m1_neg_rem_depressed, show.se = T, show.aic = T, transform = NULL, dv.labels = c('control', 'remitted', 'depressed'))$knitr) 

5 Hypothesis 2: Current Affect Moderation

For H2, we want to see whether current affective states moderate the ability to recall previous affective states. That is, do current negative affect feelings moderate the relationship between affect and recall?

#create separate dataframes for each group
df_medal_clean_control = df_medal_clean %>% filter(condition=='control')
df_medal_clean_remitted = df_medal_clean %>% filter(condition=='remitted')
df_medal_clean_depressed = df_medal_clean %>% filter(condition=='depressed')

#create a new dataframe for the remote variables, where the participants with the singular datapoints are removed 
df_medal_clean_remote = df_medal_clean %>% filter (!(subjectcode == 822 | subjectcode == 906 | subjectcode == 717))

#create separate dataframes per condition 
df_medal_clean_remote_control = df_medal_clean_remote %>% filter(condition=='control')
df_medal_clean_remote_remitted = df_medal_clean_remote %>% filter(condition=='remitted')
df_medal_clean_remote_depressed = df_medal_clean_remote %>% filter(condition=='depressed')

Positive Affect

Recent

An lmer model was fitted with gaussian identity, log & inverse as well as Gamma log, inverse, and identity. The models, however, were not a good fit and the gaussian identity model coped with singularity. Hence, a normal linear regression model was fitted.

h2_pos_recent_eq = "pos_mood_cs ~ condition*rec_mem_pos_mood_cs_lag*pos_mood_cs_lag_rec + gender + age + education + (1 + rec_mem_pos_mood_cs_lag + pos_mood_cs_lag_rec|subjectcode)"

# set clusters
cl = makeCluster(ncores)
registerDoParallel(cl)

# run parallel
h2_pos_recent_models = foreach(family = model_families, .combine = 'c', .packages = c('lmerTest'),  .errorhandling = "remove") %dopar% {
  fit_all_mods(h2_pos_recent_eq, df_medal_clean, family) }
stopCluster(cl)

# print the models into a single table
asis_output( tab_model(h2_pos_recent_models,  dv.labels = names(h2_pos_recent_models), 
                       show.icc = T, show.aic = T, transform = NULL, show.se = T, digits = 3)$knitr)

Due to singularity this was determined to be the best fit for the moddel

summary(h2_pos_recent_models[[2]])
plot_diagnostics(h2_pos_recent_models)
car::vif(h2_pos_recent_models[[2]])

Follow-up

m2_pos_rec_control <- lm(pos_mood_cs ~ 1 + rec_mem_pos_mood_cs_lag*pos_mood_cs_lag_rec + gender + age + education,
                   data=df_medal_clean_control)

m2_pos_rec_remitted <- lm(pos_mood_cs ~ 1 + rec_mem_pos_mood_cs_lag*pos_mood_cs_lag_rec + gender + age + education,
                   data=df_medal_clean_remitted)

m2_pos_rec_depressed <-  lm(pos_mood_cs ~ 1 + rec_mem_pos_mood_cs_lag*pos_mood_cs_lag_rec + gender + age + education,
                   data=df_medal_clean_depressed)

asis_output(tab_model(m2_pos_rec_control, m2_pos_rec_remitted, m2_pos_rec_depressed, show.se = T, show.aic = T, transform = NULL, dv.labels = c('control', 'remitted', 'depressed'))$knitr)

Remote

An lmer model was fitted with gaussian identity, log & inverse as well as Gamma log, inverse, and identity. The models, however, were not a good fit and the gaussian identity model coped with singularity. Hence, a normal linear regression model was fitted.

h2_pos_remote_eq = "pos_mood_cs ~ condition*rem_mem_pos_mood_cs_lag*pos_mood_cs_lag_rem + gender + age + education + (1 | subjectcode)"

# set clusters
cl = makeCluster(ncores)
registerDoParallel(cl)

# run parallel
h2_pos_remote_models = foreach(family = model_families, .combine = 'c', .packages = c('lmerTest'),  .errorhandling = "remove") %dopar% {
  fit_all_mods(h2_pos_remote_eq, df_medal_clean, family) }
stopCluster(cl)

# print the models into a single table
asis_output( tab_model(h2_pos_remote_models,  dv.labels = names(h2_pos_remote_models), 
                       show.icc = T, show.aic = T, transform = NULL, show.se = T, digits = 3)$knitr)

Due to singularity a regular linear model was fitted.

summary(h2_pos_remote_models[[2]])
plot_diagnostics(h2_pos_remote_models)
car::vif(h2_pos_remote_models[[2]])

Follow-up


m2_pos_rem_control <- lm(pos_mood_cs ~ rem_mem_pos_mood_cs_lag*pos_mood_cs_lag_rem  + gender + age + education, 
                   data=df_medal_clean_remote_control)

m2_pos_rem_remitted <- lm(pos_mood_cs ~ rem_mem_pos_mood_cs_lag*pos_mood_cs_lag_rem  + gender + age + education,  
                   data=df_medal_clean_remote_remitted)

m2_pos_rem_depressed <-  lm(pos_mood_cs ~ rem_mem_pos_mood_cs_lag*pos_mood_cs_lag_rem  + gender + age + education, 
                   data=df_medal_clean_remote_depressed)

asis_output(tab_model(m2_pos_rem_control, m2_pos_rem_remitted, m2_pos_rem_depressed, show.se = T, show.aic = T, transform = NULL, dv.labels = c('control', 'remitted', 'depressed'))$knitr) 

Negative Affect

Recent

h2_neg_recent_eq = "neg_mood_cs ~ condition*rec_mem_neg_mood_cs_lag*neg_mood_cs_lag_rec + gender + age + education + (1 + rec_mem_neg_mood_cs_lag + neg_mood_cs_lag_rec|subjectcode)"

# set clusters
cl = makeCluster(ncores)
registerDoParallel(cl)

# run parallel
h2_neg_recent_models = foreach(family = model_families, .combine = 'c', .packages = c('lmerTest'),  .errorhandling = "remove") %dopar% {
  fit_all_mods(h2_neg_recent_eq, df_medal_clean, family) }
stopCluster(cl)

# print the models into a single table
asis_output( tab_model(h2_neg_recent_models, dv.labels = names(h2_neg_recent_models), 
                       show.icc = T, show.aic = T, transform = NULL, show.se = T, digits = 3)$knitr)

Check Final Model

summary(h2_neg_recent_models[[4]])
plot_diagnostics(h2_neg_recent_models) 
car::vif(h2_neg_recent_models[[4]])

Follow-up


m2_neg_rec_control <- glmer(neg_mood_cs ~ rec_mem_neg_mood_cs_lag*neg_mood_cs_lag_rec + 
                              gender + age + education + 
                              (1  + rec_mem_neg_mood_cs_lag | subjectcode) + (1 +  neg_mood_cs_lag_rec|subjectcode), 
                   data=df_medal_clean_control,
                   family = Gamma(link=identity), 
                   control = glmerControl(calc.derivs = F, optimizer='bobyqa', optCtrl=list(maxfun=1e6)))

m2_neg_rec_remitted <- glmer(neg_mood_cs ~ rec_mem_neg_mood_cs_lag*neg_mood_cs_lag_rec + gender + age + education + 
                              (1  + rec_mem_neg_mood_cs_lag | subjectcode) + (1 +  neg_mood_cs_lag_rec|subjectcode), 
                   data=df_medal_clean_remitted,
                   family = Gamma(link=identity), 
                   control = glmerControl(calc.derivs = F, optimizer='bobyqa', optCtrl=list(maxfun=1e6)))

m2_neg_rec_depressed <-  glmer(neg_mood_cs ~ rec_mem_neg_mood_cs_lag*neg_mood_cs_lag_rec + gender + age + education + 
                              (1  + rec_mem_neg_mood_cs_lag | subjectcode) + (1 +  neg_mood_cs_lag_rec|subjectcode),  
                   data=df_medal_clean_depressed,
                   family = Gamma(link=identity), 
                   control = glmerControl(calc.derivs = F, optimizer='bobyqa', optCtrl=list(maxfun=1e6)))

asis_output(tab_model(m2_neg_rec_control, m2_neg_rec_remitted, m2_neg_rec_depressed, show.se = T, show.aic = T, transform = NULL, dv.labels = c('control', 'remitted', 'depressed'))$knitr) 

Remote

h2_neg_remote_eq = "neg_mood_cs ~ condition*rem_mem_neg_mood_cs_lag*neg_mood_cs_lag_rem + gender + age + education + (1 + rem_mem_neg_mood_cs_lag + neg_mood_cs_lag_rem|subjectcode)"

# set clusters
cl = makeCluster(ncores)
registerDoParallel(cl)

# run parallel
h2_neg_remote_models = foreach(family = model_families, .combine = 'c', .packages = c('lmerTest'),  .errorhandling = "remove") %dopar% {
  fit_all_mods(h2_neg_remote_eq, df_medal_clean, family) }
stopCluster(cl)

# print the models into a single table
asis_output( tab_model(h2_neg_remote_models, dv.labels = names(h2_neg_remote_models), 
                       show.icc = T, show.aic = T, transform = NULL, show.se = T, digits = 3)$knitr)

Check Final Model

summary(h2_neg_remote_models[[4]])
plot_diagnostics(h2_neg_remote_models)
car::vif(h2_neg_remote_models[[4]])

Follow-up


m2_neg_rem_control <- glmer(neg_mood_cs ~ rem_mem_neg_mood_cs_lag*neg_mood_cs_lag_rem  + gender + age + education
                            + (1  +  rem_mem_neg_mood_cs_lag|subjectcode) + (1 + neg_mood_cs_lag_rem|subjectcode), 
                   data=df_medal_clean_remote_control,
                   family = Gamma(link=identity), 
                   control = glmerControl(calc.derivs = F, optimizer='bobyqa', optCtrl=list(maxfun=1e6)))

m2_neg_rem_remitted <- glmer(neg_mood_cs ~ rem_mem_neg_mood_cs_lag*neg_mood_cs_lag_rem  + gender + age + education
                            + (1  +  rem_mem_neg_mood_cs_lag|subjectcode) + (1 + neg_mood_cs_lag_rem|subjectcode),
                   data=df_medal_clean_remote_remitted,
                   family = Gamma(link=identity), 
                   control = glmerControl(calc.derivs = F, optimizer='bobyqa', optCtrl=list(maxfun=1e6)))

m2_neg_rem_depressed <-  glmer(neg_mood_cs ~ rem_mem_neg_mood_cs_lag*neg_mood_cs_lag_rem  + gender + age + education
                            + (1  +  rem_mem_neg_mood_cs_lag|subjectcode) + (1 + neg_mood_cs_lag_rem|subjectcode), 
                   data=df_medal_clean_remote_depressed,
                   family = Gamma(link=identity), 
                   control = glmerControl(calc.derivs = F, optimizer='bobyqa', optCtrl=list(maxfun=1e6)))

asis_output(tab_model(m2_neg_rem_control, m2_neg_rem_remitted, m2_neg_rem_depressed, show.se = T, show.aic = T, transform = NULL, dv.labels = c('control', 'remitted', 'depressed'))$knitr) 

6 Exploratory Analyses

6.1 Mediation Models

Following the tests we ran for hypothesis 1, we would also like to see whether or not mediation effects exist.

RecPA


#create a new dataframe for the remote variables, where the participants with the singular datapoints are removed 
df_medal_moderation =  df_medal_clean %>% 
  filter (!(subjectcode == 822 | subjectcode == 906 | subjectcode == 717)) %>% 
  filter(!(is.na(pos_mood) | is.na(rec_mem_pos_mood_lag))) 

# med model
med_fit_h1_pos_rec <- lme4::lmer(rec_mem_pos_mood_lag ~ condition_dummy +
                                   age + gender + education + 
                                   (1 |subjectcode),
                                 data = df_medal_moderation)
# full model
out_fit_h1_pos_rec <-lme4::lmer(pos_mood ~ condition_dummy + rec_mem_pos_mood_lag +
                                  age + gender +education +
                                  (1 + rec_mem_pos_mood_lag |subjectcode), 
                                data = df_medal_moderation)

#mediation analysis for control and depressed
med_pos_rec_dep <- mediation::mediate(med_fit_h1_pos_rec, out_fit_h1_pos_rec,
                                      treat = 'condition_dummy' , control.value = 1, treat.value = 3 ,  mediator = 'rec_mem_pos_mood_lag', 
                                      sims=10000)
summary(med_pos_rec_dep)

RemNA

df_medal_moderation = df_medal_clean_remote %>% filter(!(is.na(neg_mood) | is.na(rec_mem_neg_mood_lag))) 

# med model
med_fit_h1_neg_rec <- lme4::lmer(rec_mem_neg_mood_lag ~ condition_dummy +
                                   age + gender + education +  
                                   (1 |subjectcode), 
                                 data = df_medal_moderation)
# full model
out_fit_h1_neg_rec <- lme4::lmer(neg_mood ~ condition_dummy + rec_mem_neg_mood_lag +
                                  age + gender +education + 
                                  (1 + rec_mem_neg_mood_lag|subjectcode), 
                                data = df_medal_moderation)


#mediation analysis for control and remitted
summary(mediation::mediate(med_fit_h1_neg_rec, out_fit_h1_neg_rec, 
                           treat = 'condition_dummy' , mediator = 'rec_mem_neg_mood_lag', control.value = 1, treat.value = 2 ,   
                           sims=10000))

#mediation analysis for control and depressed
summary(mediation::mediate(med_fit_h1_neg_rec, out_fit_h1_neg_rec, 
                           treat = 'condition_dummy' ,  mediator = 'rec_mem_neg_mood_lag', control.value = 1, treat.value = 3 ,
                           sims=10000))

6.2 Moderated Mediation

RemPA-CurrPA


df_medal_moderation = df_medal_clean_remote %>% 
  filter(!(is.na(pos_mood) | is.na(rem_mem_pos_mood_lag))) 

#mediation first
med_fit_h2_pos_rem <- lme4::lmer(rem_mem_pos_mood_lag ~ condition_dummy + 
                                   age + gender + education + 
                                   (1 |subjectcode), 
                                 data =df_medal_moderation)
# full model
out_fit_h2_pos_rem <-lme4::lmer(pos_mood ~ condition_dummy + rem_mem_pos_mood_lag 
                                + age + gender +education +
                                  (1 + rem_mem_pos_mood_lag |subjectcode),
                                data=df_medal_moderation)


#mediation analysis for control and remitted
med_pos_rem_rem <- mediation::mediate(med_fit_h2_pos_rem, out_fit_h2_pos_rem, 
                                      treat = 'condition_dummy' , control.value = 1, treat.value = 2 ,  mediator = 'rem_mem_pos_mood_lag')
summary(med_pos_rem_rem)

#create new dataframes with only control remitted and only control depressed
df_medal_con_rem = df_medal_clean %>% filter(condition=='control' | condition == 'remitted')
df_medal_con_dep = df_medal_clean %>% filter(condition=='control' | condition == 'depressed')

#remitted group
df_medal_con_rem$condition_dummy = build_contrast(df_medal_con_rem$condition, 'control', 'remitted')
med_h2_pos_rem_rem <- mdt_moderated(data = df_medal_con_rem, IV =condition_dummy, DV = pos_mood, M = rem_mem_pos_mood_lag, Mod = pos_mood_lag_rem) 
rbindlist(med_h2_pos_rem_rem$paths, idcol = T)

RemNA - CurrNA

df_medal_moderation = df_medal_clean_remote %>% filter(!(is.na(neg_mood) | is.na(rem_mem_neg_mood_lag))) 

#mediation first
med_fit_h2_neg_rem <- lme4::lmer(rem_mem_neg_mood_lag ~ condition_dummy +
                                   age + gender + education +
                                   (1 |subjectcode),
                                 control = lmerControl(calc.derivs = F, optimizer='bobyqa', optCtrl=list(maxfun=1e6)),
                                 data =df_medal_moderation)

out_fit_h2_neg_rem <-lme4::lmer(neg_mood ~ condition_dummy + rem_mem_neg_mood_lag +
                                  age + gender + education +
                                  (1 + rem_mem_neg_mood_lag |subjectcode), 
                                control = lmerControl(calc.derivs = F, optimizer='bobyqa', optCtrl=list(maxfun=1e6)),
                                data=df_medal_moderation)

#mediation analysis for control and depressed
med_neg_rem_dep <- mediation::mediate(med_fit_h2_neg_rem, out_fit_h2_neg_rem,  
                                      mediator = 'rem_mem_neg_mood_lag',  treat = 'condition_dummy' , 
                                      control.value = 1, treat.value = 3 , sims=10000) 
summary(med_neg_rem_dep)

#mediation analysis for control and remitted
med_neg_rem_rem <- mediation::mediate(med_fit_h2_neg_rem, out_fit_h2_neg_rem, treat = 'condition_dummy' , control.value = 1, treat.value = 2 ,  mediator = 'rem_mem_neg_mood_lag', sims=10000) 
summary(med_neg_rem_rem)

#create new dataframes with only control remitted and only control depressed
df_medal_con_rem = df_medal_clean %>% filter(condition=='control' | condition == 'remitted')
df_medal_con_dep = df_medal_clean %>% filter(condition=='control' | condition == 'depressed')

#remitted group
df_medal_con_rem$condition_dummy = build_contrast(df_medal_con_rem$condition, 'control', 'remitted')
med_h2_neg_rem_rem <- mdt_moderated(data = df_medal_con_rem, IV = condition_dummy, DV = neg_mood, M = rem_mem_neg_mood_lag, Mod = neg_mood_lag_rem) 
rbindlist(med_h2_neg_rem_rem$paths, idcol = T)

#depressed group
df_medal_con_dep$condition_dummy = build_contrast(df_medal_con_dep$condition, 'control', 'depressed')
med_h2_neg_rem_dep <- mdt_moderated(data = df_medal_con_dep, IV = condition_dummy, DV = neg_mood, M = rem_mem_neg_mood_lag, Mod = neg_mood_lag_rem) 
rbindlist(med_h2_neg_rem_dep$paths,idcol = T)
  

6.3 Context

asis_output(tab_model( (lmer(pos_mood_cs ~ rec_mem_pos_mood_cs_lag*context_location + (1  | subjectcode), data = df_medal_clean)), 
           (lmer(pos_mood_cs ~ rem_mem_pos_mood_cs_lag*context_location + (1  | subjectcode), data = df_medal_clean)),
            (lmer(neg_mood_cs ~ rem_mem_neg_mood_cs_lag*context_location + (1  | subjectcode), data = df_medal_clean)),
             (lmer(neg_mood_cs ~ rem_mem_neg_mood_cs_lag*context_location + (1  | subjectcode), data = df_medal_clean)))$knitr)

6.4 SRET

In addition to the EMA, participants also completed the SRET. This is a lab based memory bias measure. We want to check whether our memory bias measures from real-life are linked to ones from the lab in this supplementary analysis.


library('haven')
sret_file = file.path("Z:/", "inbox", "transfer-2023-12-07-02-15-pm", 'MEDAL_pre and post quest and remote recall_workfile!!_for paper only var.sav')
sret_data = read_sav(sret_file) 
sret_data = sret_data %>% select(c(1,4)) %>% distinct()

df_medal_rec_cor1 = df_medal_clean %>%
  dplyr::select(subjectcode, pos_mood, rec_mem_pos_mood_lag) %>%
  na.omit() %>% 
  dplyr::group_by(subjectcode) %>%
  dplyr::mutate(corr =  tryCatch(cor(rec_mem_pos_mood_lag, pos_mood), warning = function(e) NA),
                model_type = "PA_REC") %>% 
  dplyr::select(subjectcode, corr, model_type) %>% 
  dplyr::distinct()  %>% ungroup()


df_medal_rec_cor2 = df_medal_clean %>%
  dplyr::select(subjectcode, neg_mood, rec_mem_neg_mood_lag) %>%
  na.omit() %>% 
  dplyr::group_by(subjectcode) %>%
  dplyr::mutate(corr =  tryCatch(cor(rec_mem_neg_mood_lag, neg_mood), warning = function(e) NA),
                model_type = "NA_REC") %>% 
  dplyr::select(subjectcode, corr, model_type) %>% 
  dplyr::distinct() %>% ungroup()


df_medal_rem_cor1 = df_medal_clean %>%
  dplyr::select(subjectcode, pos_mood, rem_mem_pos_mood_lag) %>%
  na.omit() %>% 
  dplyr::group_by(subjectcode) %>%
  dplyr::mutate(corr = tryCatch(cor(rem_mem_pos_mood_lag, pos_mood), warning = function(e) NA),
                model_type = "PA_REM") %>% 
  dplyr::select(subjectcode, corr, model_type) %>% 
  dplyr::distinct()

df_medal_rem_cor2 = df_medal_clean %>%
  dplyr::select(subjectcode, neg_mood, rem_mem_neg_mood_lag) %>%
  na.omit() %>% 
  dplyr::group_by(subjectcode) %>%
  dplyr::mutate(corr = tryCatch(cor(rem_mem_neg_mood_lag, neg_mood), warning = function(e) NA),
                model_type = "NA_REM") %>% 
  dplyr::select(subjectcode, corr, model_type) %>% 
  dplyr::distinct()


df_cors = rbindlist(list(df_medal_rec_cor1, df_medal_rec_cor2, df_medal_rem_cor1, df_medal_rem_cor2))

df_ref = merge(sret_data, df_cors, by.x = 'subject', by.y = 'subjectcode')
df_ref = df_ref %>% rename(SRET = SRET_BiasGotlib_neg) %>% dplyr::mutate(group = ifelse(subject<800, "remitted", 
                                                                    ifelse(subject>=900, "control", 'depressed')) )


for (mod_type in c("PA_REC", "PA_REM", "NA_REC", "NA_REM")){
  print(mod_type)
  print(summary(lm(SRET ~ corr*group, data = df_ref %>% filter(model_type == mod_type))))
}

6.5 Relative Bias

Here we want to check for the relative NA/PA bias. So we extact the random effects from the models to get the slopes for each subject, and then compare the NA/PA slopes. This tells us if theres a bias between negative and positive memory.


# Get individual slopes
pos_rec_ref = as.data.frame(ranef(h1_pos_recent_models[[2]])) %>% filter(term!='(Intercept)') %>% select(c(3:5))
pos_rem_ref = as.data.frame(ranef(h1_pos_remote_models[[2]])) %>% filter(term!='(Intercept)') %>% select(c(3:5))
neg_rec_ref = as.data.frame(ranef(h1_neg_recent_models[[4]])) %>% filter(term!='(Intercept)') %>% select(c(3:5))
neg_rem_ref = as.data.frame(ranef(h1_neg_remote_models[[4]])) %>% filter(term!='(Intercept)') %>% select(c(3:5))
pos_rec_ref$mod = "PA_REC"
pos_rem_ref$mod = "PA_REM"
neg_rec_ref$mod = "NA_REC"
neg_rem_ref$mod = "NA_REM"

# Put together into a new data frame
df_ref = rbindlist(list(pos_rec_ref, pos_rem_ref, neg_rec_ref, neg_rem_ref))
df_ref = df_ref %>% 
  dplyr::mutate(sub = as.numeric(as.character(grp))) %>%
  dplyr::mutate(group = ifelse(sub <= 800, "remitted", 
                               ifelse(sub>=900, "control", 'depressed')) )

df_ref_rec = df_ref %>% filter(mod == 'PA_REC' | mod=='NA_REC')
df_ref_rem = df_ref %>% filter(mod == 'PA_REM' | mod=='NA_REM')
summary(lmer(condsd ~ mod*group + (1|sub), data = df_ref_rec))
summary(lmer(condsd ~ mod*group + (1|sub), data = df_ref_rem))

7 Plots

First we set our theme and fix the data for the figures we want

# Theme
ggtheme = theme(text = element_text(size = 8), 
                panel.background = element_rect(fill = "transparent"), 
                panel.grid.major = element_line(color = "grey90"),
                panel.grid.minor = element_line(color = "grey100"),
                panel.border = element_rect(color = "grey80", fill = "transparent"))

# Estimate the SD
df_medal_clean2 = df_medal_clean %>% 
  mutate(pos_mood_sd = ifelse( (pos_mood_cs_lag_rec > (mean(pos_mood_cs_lag_rec, na.rm=T)+sd(pos_mood_cs_lag_rec, na.rm=T))), "+1SD",
                               ifelse( (pos_mood_cs_lag_rec < (mean(pos_mood_cs_lag_rec, na.rm=T)-sd(pos_mood_cs_lag_rec, na.rm =T))), "-1SD", "Mean"))) %>% 
    mutate(neg_mood_sd = ifelse( (neg_mood_cs_lag_rec > (mean(neg_mood_cs_lag_rec, na.rm=T)+sd(neg_mood_cs_lag_rec, na.rm=T))), "+1SD",
                               ifelse( (neg_mood_cs_lag_rec < (mean(neg_mood_cs_lag_rec, na.rm=T)-sd(neg_mood_cs_lag_rec, na.rm =T))), "-1SD", "Mean")))

# Fix factor levels
df_medal_clean2$Condition =  factor(df_medal_clean2$condition, levels=c('control', 'remitted', 'depressed' ), labels=c('Never-Depressed', 'Remitted', 'Depressed'))
df_medal_clean2$pos_mood_sd =  factor(df_medal_clean2$pos_mood_sd, levels=c('-1SD', 'Mean', '+1SD' ))
df_medal_clean2$neg_mood_sd =  factor(df_medal_clean2$neg_mood_sd, levels=c('-1SD', 'Mean', '+1SD' ))

7.0.1 PA-CUR-REC


# Plot
plot_pa_rec = ggplot(df_medal_clean2, aes(x = rec_mem_pos_mood_c_lag, y=pos_mood_c, color = pos_mood_sd, fill = pos_mood_sd)) +
  geom_smooth(method = 'lm', alpha = 0.15) +
  labs( x = bquote(paste(REC[PM], " (subject-centered a.u.)")), y = "PM (subject-centered a.u.)", color = bquote(CUR[PM]), fill = bquote(CUR[PM]) ) +
  ggtheme + 
  facet_grid(.~Condition) 
plot_pa_rec

7.0.2 PA-CUR-REC


# Plot
plot_na_rec = 
  ggplot(df_medal_clean2, aes(x = rec_mem_neg_mood_c_lag, y=neg_mood_c, color = neg_mood_sd, fill = neg_mood_sd)) +
  geom_smooth(method = 'lm', alpha = 0.15) +
  labs( x = bquote(paste(REC['NM'], " (subject-centered a.u.)")), y = "NM (subject-centered a.u.)", color = bquote(CUR["NM"]), fill = bquote(CUR["NM"]) )+
  ggtheme + 
  facet_grid(.~Condition) 
plot_na_rec

7.0.3 Combined Plot for pub

ggarrange(NA, plot_pa_rec, NA,  plot_na_rec,
          widths=c(0.05, 1, 0.05, 1), ncol = 2, nrow = 2,
          labels=c("A", NA, "B"))
ggsave("figures/figure_2_threewayInteraction.pdf", device = 'pdf', dpi = 320, height = 6)
LS0tDQp0aXRsZTogJ0Vtb3Rpb25hbCBNZW1vcnkgaW4gRGFpbHkgTGlmZScNCmF1dGhvcjogUmF5eWFuIFR1dHVuamksIE5vYSBNYWd1c2luLCBOZXNzYSBJa2FuaSwgSmFubmEgVnJpanNlbg0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOg0KICAgIGZpZ193aWR0aDogOA0KICAgIGZpZ19oZWlnaHQ6IDgNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0aGVtZTogZmxhdGx5DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCiAgICBkZl9wcmludDogcGFnZWQNCi0tLQ0KDQojIEludHJvZHVjdGlvbg0KDQpUaGlzIG5vdGVib29rIGNvbnRhaW5zIGFuYWx5c2VzIGZyb20gdGhlIE1FREFMIHN0dWR5LCBhc3Nlc3NpbmcgbWVtb3J5IGJpYXMgaW4gcmVtaXR0ZWQgYW5kIGRlcHJlc3NlZCBpbmRpdmlkdWFscy4gVGhlIHByZS1yZWdpc3RyYXRpb24gZm9yIHRoZSBtYWluIGFuYWx5c2VzLCBhcyB3ZWxsIGFzIGEgcHJlcHJpbnQgdmVyc2lvbiBvZiB0aGUgYWNjb21wYW55aW5nIGFydGljbGUgY2FuIGJlIGZvdW5kIFtoZXJlXShodHRwczovL29zZi5pby96dWZqcy8pIGFzIHdlbGwuIFRoZSBtYWluIGFpbSBvZiB0aGUgY3VycmVudCB3b3JrIHdhcyB0byBleGFtaW5lIGhvdyB0aHJlZSBncm91cHMgKGNvbnRyb2wsIHJlbWl0dGVkLCBkZXByZXNzZWQpIGRpZmZlciBpbiB0ZXJtcyBvZiBlbW90aW9uYWwgbWVtb3J5IGR5bmFtaWNzIGluIGEgcmVhbC1saWZlIHNldHRpbmcuDQoNCmBgYHtyIG1lc3NhZ2U9VFJVRSwgd2FybmluZz1GQUxTRX0NCiNMb2FkIHBhY2thZ2VzIA0KcmVudjo6YWN0aXZhdGUoKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoamFuaXRvcikNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShkYXRhLnRhYmxlKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShwc3ljaCkNCmxpYnJhcnkoZGV2dG9vbHMpDQpsaWJyYXJ5KHBhc3RlY3MpDQpsaWJyYXJ5KGNsaSkNCmxpYnJhcnkobG1lclRlc3QpICNsaW5lYXIgbWl4ZWQgbW9kZWxzIA0KbGlicmFyeShwZXJmb3JtYW5jZSkgI2ZpdHMgb2YgcmVzaWR1YWxzIA0KbGlicmFyeShEZXNjVG9vbHMpDQpsaWJyYXJ5KHRpZHlyKSAjIFNlcGFyYXRlIHRyaWdnZXIgY29sdW1uDQpsaWJyYXJ5KHNqUGxvdCkgIyBmb3IgbmljZSB0YWJsZXMgYW5kIGludGVyYWN0aW9uIHBsb3RzIA0KbGlicmFyeShrbml0cikgIyB0byBwcmludCB0aGUgdGFibGVzIHdpdGhpbiBub3RlYm9vaw0KbGlicmFyeShmb3JlYWNoKSAjcnVuIHBhcmFsbGVsIGxvb3BzDQpsaWJyYXJ5KHBhcmFsbGVsKQ0KbGlicmFyeShkb1BhcmFsbGVsKSAjcnVuIHBhcmFsbGVsIGxvb3BzDQpsaWJyYXJ5KGdncHVicikgIyBlbW1lYW5zDQpsaWJyYXJ5KG1lZGlhdGlvbikgI21lZGlhdGlvbiBhbmFseXNpcyANCmxpYnJhcnkocGxvdGx5KSAjZm9yIGludGVyYWN0aXZlIHBsb3RzDQpsaWJyYXJ5KGp0b29scykgI2ZvciB0aGVtZV9hcGENCmxpYnJhcnkoSlNtZWRpYXRpb24pICNtb2RlcmF0ZWQgbWVkaWF0aW9uDQpsaWJyYXJ5KHdlc2FuZGVyc29uKSANCnNvdXJjZSgiZnVuY3Rpb25zLlIiKQ0KYGBgDQoNCiMgRGF0YQ0KDQpIZXJlIHdlIGxvYWQgaW4gb3VyIGRhdGEgYW5kIHByZXByb2Nlc3MgaXQgaW4gc3RlcHMuIFdlIGZpcnN0IG5lZWQgdG8gc2VwYXJhdGUgdGhlIGRpZmZlcmVudCBzdXJ2ZXlzIHRoYXQgd2VyZSBkZWxpdmVyZWQgdG8gYnJpbmcgdGhlbSBpbnRvIHRoZSBzYW1lIHNhbXBsaW5nIHRpbWVzLCBtZXJnZSBpbiBzb21lIGRlc2NyaXB0aXZlcyB3ZSBuZWVkIGFzIGNvdmFyaWF0ZXMsIGFuZCBlc3RpbWF0ZSBzdWJqZWN0LWNlbnRlcmVkIGFuZCBsYWdnZWQgdmFyaWFibGVzIGZvciBvdXIgbW9kZWxzIGxhdGVyLiANCg0KDQoxLiBMb2FkIGFuZCBjbGVhbiBkYXRhDQoNCmBgYHtyfQ0KIyBMb2FkIHRoZSBkYXRhDQpNRURBTF9FU01fY29tcGxlZXQgPC0gcmVhZF9leGNlbCgiZGF0YS9NRURBTF9FU01fY29tcGxlZXQueGxzeCIpDQojIE1vdmUgdmFyaWFibGVzIGFyb3VuZCBhbmQgY2xlYW4gbmFtZXMNCk1FREFMX0VTTV9jb21wbGVldD0gTUVEQUxfRVNNX2NvbXBsZWV0ICU+JQ0KICByZW5hbWUoaWQ9J01vdmlzZW5zLUlEJykgJT4lIA0KICBjbGVhbl9uYW1lcygpICU+JQ0KICByZW5hbWUoc3ViamVjdGNvZGUgPSAnZGVlbG5lbWVyc25yJykgJT4lIA0KICByZWxvY2F0ZSgnc3ViamVjdGNvZGUnLCAuYWZ0ZXIgPSAnaWQnKQ0KZGZfbWVkYWxfdHJ5ID0gTUVEQUxfRVNNX2NvbXBsZWV0DQoNCmBgYA0KDQoyLiBTcGxpdCBkaWZmZXJlbnQgRU1BIHN1cnZleXMgd2UgaGF2ZQ0KDQpgYGB7cn0NCiMgU2xlZXAgRU1BIFFzDQpkZl9tZWRhbF9zbGVlcCA9IGRmX21lZGFsX3RyeSAlPiUgDQogIGZpbHRlcihmb3JtPT0nU2xhYXAnKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoYygxLCAyLCA0LCA1LCA3LCA5LCAxNCkpIA0KIyBSZWNlbnQgRU1BIFFzDQpkZl9tZWRhbF9yZWNlbnQgPSBkZl9tZWRhbF90cnkgJT4lIA0KICBmaWx0ZXIoZm9ybT09J1JlY2VudCcpICU+JSANCiAgZHBseXI6OnNlbGVjdChjKDEsIDIsIDQsIDUsIDcsIDksIGNvbnRhaW5zKCdyZWMnKSkpDQojIFJlbW90ZSBFTUEgUXMNCmRmX21lZGFsX3JlbW90ZSA9IGRmX21lZGFsX3RyeSAlPiUNCiAgZmlsdGVyKGZvcm09PSdSZW1vdGUnKSAlPiUNCiAgZHBseXI6OnNlbGVjdChjKDEsIDIsIDQsIDUsIDcsIDksIGNvbnRhaW5zKCdyZW0nKSkpDQojIE1hc3RlcnkgRU1BIFFzDQpkZl9tZWRhbF9tYXN0ZXJ5ID0gZGZfbWVkYWxfdHJ5ICU+JQ0KICBmaWx0ZXIoZm9ybT09J01hc3RlcnknKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoYygxLCAyLCA0LCA1LCA3LCA5LCBjb250YWlucygnbWFzdGVyJykpKQ0KIyBTdGFuZGFyZCBRcw0KZGZfbWVkYWxfc3RhbmRhcmQgPSBkZl9tZWRhbF90cnkgJT4lDQogIGZpbHRlcihmb3JtPT0nU3RhbmRhYXJkJykgICU+JQ0KICBkcGx5cjo6c2VsZWN0KGMoMSwgMiwgNCwgNSwgNywgOSwgKC1jb250YWlucygnbWFzdGVyeScpICYgLWNvbnRhaW5zKCdyZW0nKSAmIC1jb250YWlucygncmVjJykpKSkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC1jKDcsMTMsMTQpKQ0KDQojIG1lcmdlIHNsZWVwIGFuZCBzdGFuZGFyZA0KZGZfbWVkYWxfbWVyZ2VkID0gbWVyZ2UoZGZfbWVkYWxfc2xlZXAsIGRmX21lZGFsX3N0YW5kYXJkLCBieT1jKCdpZCcsICd0cmlnZ2VyX2NvdW50ZXInLCAnc3ViamVjdGNvZGUnKSwgc3VmZml4ZXMgPSBjKCJfc2xlZXAiLCAiIiksIGFsbD1UICkNCg0KIyBtZXJnZSB0byByZWNlbnQsIHJlbW90ZSBhbmQgbWFzdGVyeQ0KZGZfbWVkYWxfbWVyZ2VkPSBtZXJnZShkZl9tZWRhbF9tZXJnZWQsIGRmX21lZGFsX3JlY2VudCwgYnk9YygnaWQnLCAndHJpZ2dlcl9jb3VudGVyJywgJ3N1YmplY3Rjb2RlJyApLCBzdWZmaXhlcyA9IGMoJycsICdfcmVjZW50JyksIGFsbCA9IFQgKQ0KZGZfbWVkYWxfbWVyZ2VkID0gbWVyZ2UoZGZfbWVkYWxfbWVyZ2VkLCBkZl9tZWRhbF9yZW1vdGUsIGJ5PWMoJ2lkJywgJ3RyaWdnZXJfY291bnRlcicsICdzdWJqZWN0Y29kZScgKSwgc3VmZml4ZXMgPSBjKCcnLCAnX3JlbW90ZScpLCBhbGwgPSBUICkNCmRmX21lZGFsX21lcmdlZCA9IG1lcmdlKGRmX21lZGFsX21lcmdlZCwgZGZfbWVkYWxfbWFzdGVyeSwgYnk9YygnaWQnLCAndHJpZ2dlcl9jb3VudGVyJywgJ3N1YmplY3Rjb2RlJyApLCBzdWZmaXhlcyA9IGMoJycsICdfbWFzdGVyeScpLCBhbGwgPSBUICkNCg0KIyBGaXggc3RhcnQgZGF0ZXMgYW5kIHRpbWVzDQpkZl9tZWRhbF9tZXJnZWQkZm9ybV9zdGFydF9kYXRlIDwtIGFzLmNoYXJhY3RlcihkZl9tZWRhbF9tZXJnZWQkZm9ybV9zdGFydF9kYXRlKQ0KZGZfbWVkYWxfbWVyZ2VkJGZvcm1fc3RhcnRfZGF0ZSA8LSBhcy5JVGltZShkZl9tZWRhbF9tZXJnZWQkZm9ybV9zdGFydF9kYXRlKQ0KZGZfbWVkYWxfbWVyZ2VkID0gZGZfbWVkYWxfbWVyZ2VkICU+JSANCiAgZHBseXI6Om11dGF0ZShmb3JtX3N0YXJ0X2RhdGUgPSBpZmVsc2UoaXMubmEoZm9ybV9zdGFydF9kYXRlKSwgZm9ybV9zdGFydF9kYXRlX3NsZWVwLCBmb3JtX3N0YXJ0X2RhdGUpKQ0KYGBgDQoNCjMuIEFkZCB2YXJpYWJsZXMgb24gRWR1Y2F0aW9uLCBHZW5kZXIsIGFuZCBBZ2UNCg0KYGBge3J9DQojIExvYWQgaW4gcHJldmlvdXMgZGF0YSBmb3IgZGVtb2dyYXBoaWNzIChhbHNvIGNvbnRhaW5zIEVNQSkNCmxvYWQoImRhdGEvSVBBUV9NYWV2ZV9Xb3Jrc3BhY2UuUkRhdGEiKQ0KZGZfTUVEQUwgPC0gZGZfTUVEQUxbLWMoMTkyKSwgXQ0KDQojIFNlbGVjdCByZWxldmFudCBkZW1vIGluZm8NCmRmX01FREFMID0gZGZfTUVEQUwgJT4lIA0KICBkcGx5cjo6c2VsZWN0KDEsIDMsIDU6NykgJT4lIA0KICByZW5hbWUoJ3N1YmplY3Rjb2RlJyA9ICdzdWJqZWN0JywgJ2VkdWNhdGlvbicgPSAnRWR1Y2F0aW9uM2dyb3VwcycsICduX2VwaXNvZGVzJz0nTnVtYmVyRXBpc29kZXMnICkNCg0KIyBtZXJnZSBkZW1vIHRvIGZ1bGwgRU1BDQpkZl9tZWRhbF9tZXJnZWQgPSAgbWVyZ2UoZGZfbWVkYWxfbWVyZ2VkLCBkZl9NRURBTCwgYnkgPSBjKCdzdWJqZWN0Y29kZScpLCBhbGwgPSBUICkgJT4lDQogIGNsZWFuX25hbWVzKCkgDQoNCmRmX21lZGFsX21lcmdlZCRlZHVjYXRpb24gPSBhcy5mYWN0b3IoZGZfbWVkYWxfbWVyZ2VkJGVkdWNhdGlvbikNCmRmX21lZGFsX21lcmdlZCRnZW5kZXIgPSBhcy5mYWN0b3IoZGZfbWVkYWxfbWVyZ2VkJGdlbmRlcikNCg0KZGZfbWVkYWxfbWVyZ2VkID0gZGZfbWVkYWxfbWVyZ2VkICU+JSANCiAgcmVsb2NhdGUoYygnaWQnLCAnZ2VuZGVyJywgJ2FnZScsICdlZHVjYXRpb24nKSwgLmFmdGVyID0gJ3N1YmplY3Rjb2RlJykgJT4lIA0KICByZWxvY2F0ZSAoJ2FnZScsIC5hZnRlciA9ICdnZW5kZXInKSAlPiUgDQogIHJlbG9jYXRlICgnZWR1Y2F0aW9uJywgLmFmdGVyID0gJ2FnZScpICU+JSANCiAgcmVsb2NhdGUgKCdpZCcsIC5iZWZvcmUgPSAnc3ViamVjdGNvZGUnKQ0KDQpgYGANCg0KNC4gQ2F0ZWdvcml6ZSB0aGUgc3ViamVjdGNvZGUgaW50byB0aGUgdGhyZWUgY29uZGl0aW9ucyAoRGVwcmVzc2VkLCBSZW1pdHRlZCwgQ29udHJvbCAoTmV2ZXItZGVwcmVzc2VkKSkNCg0KYGBge3J9DQpkZl9tZWRhbF9tZXJnZWQkY29uZGl0aW9uID0gY2FzZV93aGVuKGRmX21lZGFsX21lcmdlZCRzdWJqZWN0Y29kZSA+PSA3MDAgJiBkZl9tZWRhbF9tZXJnZWQkc3ViamVjdGNvZGUgPCA4MDAgfiAicmVtaXR0ZWQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZl9tZWRhbF9tZXJnZWQkc3ViamVjdGNvZGUgPj0gODAwICYgZGZfbWVkYWxfbWVyZ2VkJHN1YmplY3Rjb2RlIDwgOTAwIH4gImRlcHJlc3NlZCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZl9tZWRhbF9tZXJnZWQkc3ViamVjdGNvZGUgPj0gOTAwIH4gImNvbnRyb2wiKQ0KZGZfbWVkYWxfbWVyZ2VkID0gZGZfbWVkYWxfbWVyZ2VkICU+JSByZWxvY2F0ZSAoJ2NvbmRpdGlvbicsIC5hZnRlciA9ICdzdWJqZWN0Y29kZScgKQ0KZGZfbWVkYWxfbWVyZ2VkJGNvbmRpdGlvbiA8LSBhcy5mYWN0b3IoZGZfbWVkYWxfbWVyZ2VkJGNvbmRpdGlvbikNCmBgYA0KDQo1LiBDYWxjdWxhdGUgcmVhY3Rpb24gdGltZSANCg0KYGBge3J9DQpkZl9tZWRhbF9tZXJnZWQkcnRfc2xlZXAgPSBsdWJyaWRhdGU6OmFzLmRpZmZ0aW1lKCBkZl9tZWRhbF9tZXJnZWQkZm9ybV9maW5pc2hfZGF0ZV9zbGVlcCAtIGRmX21lZGFsX21lcmdlZCRmb3JtX3N0YXJ0X2RhdGVfc2xlZXApDQpgYGANCg0KNi4gU2VwYXJhdGUgdGltZSBmcm9tIHdoZW4gdHJpZ2dlciB3YXMgc2VudA0KDQpgYGB7cn0NCg0KZGZfbWVkYWxfbWVyZ2VkID0gZGZfbWVkYWxfbWVyZ2VkICU+JSANCiAgdGlkeXI6OnNlcGFyYXRlKHRyaWdnZXIsIGMoJ1JhbmRvbScsICdUaW1lJywgJ1RyaWdnZXJfVGltZV8xJywgJ1RyaWdnZXJfVGltZV8yJykpICAlPiUgDQogIGRwbHlyOjptdXRhdGUodHJpZ2dlcl90aW1lID0gcGFzdGUoVHJpZ2dlcl9UaW1lXzEsIFRyaWdnZXJfVGltZV8yLCBzZXA9JzonKSkgJT4lI3NlcGFyYXRlIHRpbWUgZnJvbSBwcmV2aW91cyB0cmlnZ2VyDQogIGRwbHlyOjptdXRhdGUodHJpZ2dlciA9IHBhc3RlKFJhbmRvbSwgVGltZSwgdHJpZ2dlcl90aW1lLCBzZXA9JyAnKSkgI2JyaW5nIGJhY2sgJ3RyaWdnZXInIGNvbHVtbiANCg0KI1R1cm4gbnVtYmVycyBpbnRvIHRpbWUgZm9ybWF0DQpkZl9tZWRhbF9tZXJnZWQkdHJpZ2dlcl90aW1lIDwtIGFzLklUaW1lKGRmX21lZGFsX21lcmdlZCR0cmlnZ2VyX3RpbWUpDQpgYGANCg0KNy4gRmluZCB0aGUgdHJpZ2dlciBudW1iZXIgcGVyIGRheQ0KDQpgYGB7cn0NCiNkZl9tZWRhbF9tZXJnZWQkdHJpZ2dlcl9jb3VudGVyW2lzLm5hKGRmX21lZGFsX21lcmdlZCR0cmlnZ2VyX3RpbWUpXSA8LSAxDQoNCmRmX21lZGFsX21lcmdlZCR0cmlnZ2VyX251bWJlcltpcy5uYShkZl9tZWRhbF9tZXJnZWQkdHJpZ2dlcl90aW1lKV0gPC0gMSANCmRmX21lZGFsX21lcmdlZCR0cmlnZ2VyX251bWJlcltkZl9tZWRhbF9tZXJnZWQkdHJpZ2dlcl90aW1lID49IChhcy5JVGltZSgiMTA6MDA6MDAiKSkmIGRmX21lZGFsX21lcmdlZCR0cmlnZ2VyX3RpbWUgPCAoYXMuSVRpbWUoIjEyOjAwOjAwIikpXSA8LSAyDQpkZl9tZWRhbF9tZXJnZWQkdHJpZ2dlcl9udW1iZXJbZGZfbWVkYWxfbWVyZ2VkJHRyaWdnZXJfdGltZSA+PSAoYXMuSVRpbWUoIjEyOjAwOjAwIikpJiBkZl9tZWRhbF9tZXJnZWQkdHJpZ2dlcl90aW1lIDwgKGFzLklUaW1lKCIxNDowMDowMCIpKV0gPC0gMw0KZGZfbWVkYWxfbWVyZ2VkJHRyaWdnZXJfbnVtYmVyW2RmX21lZGFsX21lcmdlZCR0cmlnZ2VyX3RpbWUgPj0gKGFzLklUaW1lKCIxNDowMDowMCIpKSYgZGZfbWVkYWxfbWVyZ2VkJHRyaWdnZXJfdGltZSA8IChhcy5JVGltZSgiMTY6MDA6MDAiKSldIDwtIDQNCmRmX21lZGFsX21lcmdlZCR0cmlnZ2VyX251bWJlcltkZl9tZWRhbF9tZXJnZWQkdHJpZ2dlcl90aW1lID49IChhcy5JVGltZSgiMTY6MDA6MDAiKSkmIGRmX21lZGFsX21lcmdlZCR0cmlnZ2VyX3RpbWUgPCAoYXMuSVRpbWUoIjE4OjAwOjAwIikpXSA8LSA1DQpkZl9tZWRhbF9tZXJnZWQkdHJpZ2dlcl9udW1iZXJbZGZfbWVkYWxfbWVyZ2VkJHRyaWdnZXJfdGltZSA+PSAoYXMuSVRpbWUoIjE4OjAwOjAwIikpJiBkZl9tZWRhbF9tZXJnZWQkdHJpZ2dlcl90aW1lIDwgKGFzLklUaW1lKCIyMDowMDowMCIpKV0gPC0gNg0KZGZfbWVkYWxfbWVyZ2VkJHRyaWdnZXJfbnVtYmVyW2RmX21lZGFsX21lcmdlZCR0cmlnZ2VyX3RpbWUgPj0gKGFzLklUaW1lKCIyMDowMDowMCIpKSYgZGZfbWVkYWxfbWVyZ2VkJHRyaWdnZXJfdGltZSA8IChhcy5JVGltZSgiMjM6MDA6MDEiKSldIDwtIDcNCg0KIyBkZg0KZGZfbWVkYWxfbWVyZ2VkID0gZGZfbWVkYWxfbWVyZ2VkICU+JSANCiAgcmVsb2NhdGUgKCd0cmlnZ2VyX251bWJlcicsIC5hZnRlciA9ICd0cmlnZ2VyX2NvdW50ZXInKSU+JSByZWxvY2F0ZSgndHJpZ2dlcl90aW1lJywgLmJlZm9yZSA9J2Zvcm1fc3RhcnRfZGF0ZScpICU+JQ0KICByZWxvY2F0ZSgndHJpZ2dlcicsIC5iZWZvcmUgPSd0cmlnZ2VyX3RpbWUnKQ0KYGBgDQoNCjguIEZpbmFsIGNsZWFuaW5nIG9mIHRoZSBkYXRhc2V0DQpgYGB7cn0NCg0KI0NyZWF0ZSBkYXRhc2V0IHdoZXJlIGRvdWJsZSBtb3JuaW5nIGxpc3QgaXMgcmVtb3ZlZCANCmRmX21lZGFsX21lcmdlZCA9IGRmX21lZGFsX21lcmdlZCAlPiUgDQogIGRwbHlyOjptdXRhdGUodHJpZ2dlcl9jb3VudGVyPWlmZWxzZSh0cmlnZ2VyX251bWJlcj09MSAmIGxhZyh0cmlnZ2VyX251bWJlcik9PTEsIGxhZyh0cmlnZ2VyX2NvdW50ZXIpLCB0cmlnZ2VyX2NvdW50ZXIpKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodHJpZ2dlcl9jb3VudGVyPWlmZWxzZSh0cmlnZ2VyX251bWJlcj09MSAmIGxhZyh0cmlnZ2VyX251bWJlcik9PTEsIGxhZyh0cmlnZ2VyX2NvdW50ZXIpLCB0cmlnZ2VyX2NvdW50ZXIpKSAlPiUNCiAgZHBseXI6Om11dGF0ZSh0cmlnZ2VyX2NvdW50ZXI9aWZlbHNlKHRyaWdnZXJfbnVtYmVyPT0xICYgbGFnKHRyaWdnZXJfbnVtYmVyKT09MSwgbGFnKHRyaWdnZXJfY291bnRlciksIHRyaWdnZXJfY291bnRlcikpICU+JQ0KICBkcGx5cjo6bXV0YXRlKHRyaWdnZXJfY291bnRlcj1pZmVsc2UodHJpZ2dlcl9udW1iZXI9PTEgJiBsYWcodHJpZ2dlcl9udW1iZXIpPT0xLCBsYWcodHJpZ2dlcl9jb3VudGVyKSwgdHJpZ2dlcl9jb3VudGVyKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRyaWdnZXJfY291bnRlcj1pZmVsc2UodHJpZ2dlcl9udW1iZXI9PTEgJiBsYWcodHJpZ2dlcl9udW1iZXIpPT0xLCBsYWcodHJpZ2dlcl9jb3VudGVyKSwgdHJpZ2dlcl9jb3VudGVyKSkNCg0KIyBub3cgd2UgaGF2ZSB0aGUgY2xlYW4gZGF0YWZyYW1lLCByZW1vdmUgZHVwbGljYXRlZCBjb2xvdW1ucw0KZGZfbWVkYWxfY2xlYW4gPSBkZl9tZWRhbF9tZXJnZWQgJT4lDQogIGRwbHlyOjpncm91cF9ieShzdWJqZWN0Y29kZSkgJT4lIA0KICBkaXN0aW5jdCh0cmlnZ2VyX2NvdW50ZXIsIC5rZWVwX2FsbCA9IFRSVUUpICU+JSANCiAgZHBseXI6OnNlbGVjdCAoMToxMiwgMTc6NjApICU+JSANCiAgZHBseXI6Om11dGF0ZShvcmlnaW5hbF9vcmRlciA9IHJvd19udW1iZXIoKSkgJT4lIA0KICByZWxvY2F0ZSgnb3JpZ2luYWxfb3JkZXInLCAuYmVmb3JlID0gJ2lkJykNCg0KI1NldCB0aGUgb3JkZXIgb2YgdGhlIGZhY3RvciB0byBjb250cm9sLCByZW1pc3Npb24sIGRlcHJlc3Npb24gKGZvciB2aXN1YWwgcHVycG9zZXMpDQpkZl9tZWRhbF9jbGVhbiRjb25kaXRpb24gPC0gZmFjdG9yKGRmX21lZGFsX2NsZWFuJGNvbmRpdGlvbiwgbGV2ZWxzPWMoJ2NvbnRyb2wnLCAncmVtaXR0ZWQnLCAnZGVwcmVzc2VkJyApLCBsYWJlbHM9YygnY29udHJvbCcsICdyZW1pdHRlZCcsICdkZXByZXNzZWQnKSkNCg0KIyBDcmVhdGUgZHVtbXkgdmFyaWFibGUgDQpkZl9tZWRhbF9jbGVhbiA9IGRmX21lZGFsX2NsZWFuICU+JSANCiAgbXV0YXRlKGNvbmRpdGlvbl9kdW1teSA9IGNhc2Vfd2hlbihjb25kaXRpb24gPT0gJ2RlcHJlc3NlZCd+IDMsIGNvbmRpdGlvbiA9PSAncmVtaXR0ZWQnfiAyLCBjb25kaXRpb24gPT0gJ2NvbnRyb2wnIH4gMSkpDQoNCmRmX21lZGFsX2NsZWFuJGNvbmRpdGlvbl9kdW1teSA9IGFzLmZhY3RvcihkZl9tZWRhbF9jbGVhbiRjb25kaXRpb25fZHVtbXkpDQoNCiNzZXQgd2Vla2RheSANCmRmX21lZGFsX2NsZWFuJGZvcm1fZmluaXNoX2RhdGUgPC0gYXMuY2hhcmFjdGVyKGRmX21lZGFsX2NsZWFuJGZvcm1fZmluaXNoX2RhdGUpDQpkZl9tZWRhbF9jbGVhbiRmb3JtX2ZpbmlzaF9kYXRlIDwtIHN0cnB0aW1lKGRmX21lZGFsX2NsZWFuJGZvcm1fZmluaXNoX2RhdGUsIGZvcm1hdCA9ICclWS0lbS0lZCAlSDolTTolUycpDQoNCmRmX21lZGFsX2NsZWFuJGZpbmlzaF9kYXRlIDwtIGFzLkRhdGUoZGZfbWVkYWxfY2xlYW4kZm9ybV9maW5pc2hfZGF0ZSkNCmRmX21lZGFsX2NsZWFuJHdlZWtkYXkgPC0gYXMuaW50ZWdlcihmb3JtYXQoZGZfbWVkYWxfY2xlYW4kZmluaXNoX2RhdGUsICcldycpKQ0KZGZfbWVkYWxfY2xlYW4gPSBkZl9tZWRhbF9jbGVhbiAlPiUgcmVsb2NhdGUoJ3dlZWtkYXknLCAuYWZ0ZXIgPSAndHJpZ2dlcl9udW1iZXInKQ0KDQojc29sdmUgZHVwbGljYXRlIGlzc3VlIA0KZGZfbWVkYWxfZHVwbGljYXRlID0gZGZfbWVkYWxfY2xlYW4gJT4lIGRwbHlyOjpncm91cF9ieShzdWJqZWN0Y29kZSwgd2Vla2RheSkgJT4lIGZpbHRlcihkdXBsaWNhdGVkKHRyaWdnZXJfbnVtYmVyKSkNCg0KICAjc2luY2Ugcm93IDEwIGZvciBzdWJqZWN0IDcxMiBpcyBhIGR1cGxpY2F0ZSBtb3JuaW5nIGxpc3QNCiAgZGZfbWVkYWxfY2xlYW4gPC0gc3Vic2V0KGRmX21lZGFsX2NsZWFuLCAhKHN1YmplY3Rjb2RlID09IDcxMiAmIG9yaWdpbmFsX29yZGVyID09IDEwKSkNCiAgZGZfbWVkYWxfY2xlYW4gPSBkZl9tZWRhbF9jbGVhbiAlPiUgZHBseXI6Omdyb3VwX2J5KHN1YmplY3Rjb2RlLCB3ZWVrZGF5KSAlPiUgDQogICAgbXV0YXRlKHRlbXAgPSBsZWFkKHRyaWdnZXJfbnVtYmVyKSwgDQogICAgICAgICAgIHRyaWdnZXJfbnVtYmVyID0gY2FzZV93aGVuKHRyaWdnZXJfbnVtYmVyID09IHRlbXAgfiAodGVtcCAtMSksIFRSVUUgfiB0cmlnZ2VyX251bWJlcikpICU+JQ0KICAgIHNlbGVjdCgtdGVtcCkNCiAgI1Rha2UgdGhlIHJvd3Mgb3V0IHRoYXQgaGF2ZSAnTkEnZm9yIHRoZSB3ZWVrZGF5IHNpbmNlIGZvcm0gd2Fzbid0IGZpbmlzaGVkIGFuZCB0aGVyZSBpcyBubyBkYXRhIGZvciBQQSwgTkEsIG9yIE1lbW9yeQ0KICBkZl9tZWRhbF9jbGVhbiA9IGRmX21lZGFsX2NsZWFuICU+JSBmaWx0ZXIoIWlzLm5hKHdlZWtkYXkpKQ0KICBkZl9tZWRhbF9jbGVhbiRvcmlnaW5hbF9vcmRlciA8LSAxOm5yb3coZGZfbWVkYWxfY2xlYW4pIA0KDQojIENyZWF0ZSBleHBhbmRlZCBkZiB3aXRoIGFsbCBwb3RlbnRpYWwgZGF0YXBvaW50cw0KDQpkZl9tZWRhbF9kYXkgPSBkZl9tZWRhbF9jbGVhbiAlPiUgDQogIGRwbHlyOjpzZWxlY3QoJ3N1YmplY3Rjb2RlJywgJ3dlZWtkYXknLCAnb3JpZ2luYWxfb3JkZXInKSAlPiUgDQogIGRwbHlyOjptdXRhdGUod2Vla2RheSA9IGFzLm51bWVyaWMod2Vla2RheSkpICU+JQ0KICBkcGx5cjo6Z3JvdXBfYnkoc3ViamVjdGNvZGUpICU+JQ0KICBkcGx5cjo6IGRpc3RpbmN0KHdlZWtkYXksIC5rZWVwX2FsbCA9VCkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpDQoNCmRmX21lZGFsX2RheSA9IGRmX21lZGFsX2RheSAlPiUgDQogIHNsaWNlKHJlcCgxOm4oKSwgZWFjaCA9IDcpKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodHJpZ2dlcl9udW1iZXIgPSByZXAoMTo3LCBsZW5ndGgub3V0PW4oKSkpICU+JSANCiAgZHBseXI6OnJlbmFtZShvcmRlciA9IG9yaWdpbmFsX29yZGVyKQ0KDQoNCiNtZXJnZSB3aXRoIG1haW4gZGF0YWZyYW1lDQpkZl9tZWRhbF9jbGVhbiA9ICBtZXJnZShkZl9tZWRhbF9kYXksIGRmX21lZGFsX2NsZWFuLCBieT1jKCdzdWJqZWN0Y29kZScsICd0cmlnZ2VyX251bWJlcicsICd3ZWVrZGF5JyksIGFsbD0gVCkgDQpkZl9tZWRhbF9jbGVhbiA9IGRmX21lZGFsX2NsZWFuICU+JSBtdXRhdGUob3JkZXIgPSBhcy5udW1lcmljKG9yZGVyKSkNCmRmX21lZGFsX2NsZWFuID0gYXJyYW5nZShkZl9tZWRhbF9jbGVhbiwgb3JkZXIpDQpgYGANCg0KOS4gQ2VudHJlLCBzY2FsZSwgYW5kIGF2ZXJhZ2UgVmFyaWFibGVzIA0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KDQp1c2VkX3ZhcnMgPSBjKCJuZWdfbW9vZCIsICJyZWNfbWVtX25lZ19tb29kIiwgInJlbV9tZW1fbmVnX21vb2QiLCAicG9zX21vb2QiLCAicmVjX21lbV9wb3NfbW9vZCIsICJyZW1fbWVtX3Bvc19tb29kIikNCg0KI0NlbnRlcmluZyAmIHNjYWxpbmcgDQpkZl9tZWRhbF9jbGVhbiA9IGRmX21lZGFsX2NsZWFuICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN1YmplY3Rjb2RlKSAlPiUNCiAgIyBDZW50ZXIgYW5kIHNjYWxlDQogIGRwbHlyOjptdXRhdGUoIGFjcm9zcyh1c2VkX3ZhcnMsIH4gKC54LzEwKSwgLm5hbWVzID0gInsuY29sfSIgKSwNCiAgICAgICAgICAgICAgICAgYWNyb3NzKHVzZWRfdmFycywgfiBtZWFuKC54LCBuYS5ybT1UKSwgLm5hbWVzID0gInsuY29sfV9tIiApLA0KICAgICAgICAgICAgICAgICBhY3Jvc3ModXNlZF92YXJzLCB+ICgueCAtIG1lYW4oLngsIG5hLnJtPVQpKSwgLm5hbWVzID0gInsuY29sfV9jIiApLCANCiAgICAgICAgICAgICAgICAgYWNyb3NzKHBhc3RlMCh1c2VkX3ZhcnMsICJfYyIpLCB+IERlc2NUb29sczo6V2luc29yaXplKC54LCBuYS5ybSA9IFQpLCAubmFtZXMgPSAiey5jb2x9IikpICU+JSAgDQogIHVuZ3JvdXAoKSAlPiUNCiAgIyBSZXNjYWxlIHRvIHBvc2l0aXZlDQogIG11dGF0ZShhY3Jvc3MoYyhwYXN0ZTAodXNlZF92YXJzLCJfYyIpKSwgfiBhYnMobWluKC54LCBuYS5ybSA9IFQpKSArIDEgKyAueCwgLm5hbWVzID0gInsuY29sfXMiKSkNCg0KYGBgDQoNCg0KMTAuIExhZyB2YXJpYWJsZXMgDQpgYGB7cn0NCiMgUmVtb3RlIA0KDQpkZl9tZWRhbF9jbGVhbiA9IGRmX21lZGFsX2NsZWFuICU+JQ0KICBkcGx5cjo6Z3JvdXBfYnkoc3ViamVjdGNvZGUpICU+JQ0KICBtdXRhdGUocmVtX21lbV9wb3NfbW9vZF9sYWcgPSBsZWFkKHJlbV9tZW1fcG9zX21vb2QsIG49Nywgb3JkZXJfYnk9c3ViamVjdGNvZGUpLA0KICAgICAgICAgcmVtX21lbV9uZWdfbW9vZF9sYWcgPSBsZWFkKHJlbV9tZW1fbmVnX21vb2QsIG49Nywgb3JkZXJfYnk9c3ViamVjdGNvZGUpLA0KICAgICAgICAgcG9zX21vb2RfbGFnX3JlbSA9IGxlYWQocG9zX21vb2QsIG49Nywgb3JkZXJfYnk9c3ViamVjdGNvZGUpLA0KICAgICAgICAgbmVnX21vb2RfbGFnX3JlbSA9IGxlYWQobmVnX21vb2QsIG49Nywgb3JkZXJfYnk9c3ViamVjdGNvZGUpLCANCiAgICAgICAgIHJlbV9tZW1fcG9zX21vb2RfY3NfbGFnID0gbGVhZChyZW1fbWVtX3Bvc19tb29kX2NzLCBuPTcsIG9yZGVyX2J5PXN1YmplY3Rjb2RlKSwNCiAgICAgICAgIHJlbV9tZW1fbmVnX21vb2RfY3NfbGFnID0gbGVhZChyZW1fbWVtX25lZ19tb29kX2NzLCBuPTcsIG9yZGVyX2J5PXN1YmplY3Rjb2RlKSwNCiAgICAgICAgIHBvc19tb29kX2NzX2xhZ19yZW0gPSBsZWFkKHBvc19tb29kX2NzLCBuPTcsIG9yZGVyX2J5PXN1YmplY3Rjb2RlKSwNCiAgICAgICAgIG5lZ19tb29kX2NzX2xhZ19yZW0gPSBsZWFkKG5lZ19tb29kX2NzLCBuPTcsIG9yZGVyX2J5PXN1YmplY3Rjb2RlKSwNCiAgICAgICAgIHJlbV9tZW1fcG9zX21vb2RfY19sYWcgPSBsZWFkKHJlbV9tZW1fcG9zX21vb2RfYywgbj03LCBvcmRlcl9ieT1zdWJqZWN0Y29kZSksDQogICAgICAgICByZW1fbWVtX25lZ19tb29kX2NfbGFnID0gbGVhZChyZW1fbWVtX25lZ19tb29kX2MsIG49Nywgb3JkZXJfYnk9c3ViamVjdGNvZGUpLA0KICAgICAgICAgcG9zX21vb2RfY19sYWdfcmVtID0gbGVhZChwb3NfbW9vZF9jLCBuPTcsIG9yZGVyX2J5PXN1YmplY3Rjb2RlKSwNCiAgICAgICAgIG5lZ19tb29kX2NfbGFnX3JlbSA9IGxlYWQobmVnX21vb2RfYywgbj03LCBvcmRlcl9ieT1zdWJqZWN0Y29kZSkpICU+JSANCiAgZmlsdGVyKCFpcy5uYShvcmlnaW5hbF9vcmRlcikpICMgZmlsdGVyIG91dCB0aGUgTkEgcm93cyBmb3IgdGhlIGxhZ2dpbmcgb2YgcmVjZW50IG1lbW9yeSANCg0KIyBSZWNlbnQNCmRmX21lZGFsX2NsZWFuID0gZGZfbWVkYWxfY2xlYW4gJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3ViamVjdGNvZGUpICU+JQ0KICBtdXRhdGUocmVjX21lbV9wb3NfbW9vZF9sYWcgPSBsZWFkKHJlY19tZW1fcG9zX21vb2QsIG49MSwgb3JkZXJfYnk9c3ViamVjdGNvZGUpLA0KICAgICAgICAgcmVjX21lbV9uZWdfbW9vZF9sYWcgPSBsZWFkKHJlY19tZW1fbmVnX21vb2QsIG49MSwgb3JkZXJfYnk9c3ViamVjdGNvZGUpLA0KICAgICAgICAgcG9zX21vb2RfbGFnX3JlYyA9IGxlYWQocG9zX21vb2QsIG49MSwgb3JkZXJfYnk9c3ViamVjdGNvZGUpLA0KICAgICAgICAgbmVnX21vb2RfbGFnX3JlYyA9IGxlYWQobmVnX21vb2QsIG49MSwgb3JkZXJfYnk9c3ViamVjdGNvZGUpLA0KICAgICAgICAgcmVjX21lbV9wb3NfbW9vZF9jc19sYWcgPSBsZWFkKHJlY19tZW1fcG9zX21vb2RfY3MsIG49MSwgb3JkZXJfYnk9c3ViamVjdGNvZGUpLA0KICAgICAgICAgcmVjX21lbV9uZWdfbW9vZF9jc19sYWcgPSBsZWFkKHJlY19tZW1fbmVnX21vb2RfY3MsIG49MSwgb3JkZXJfYnk9c3ViamVjdGNvZGUpLA0KICAgICAgICAgcG9zX21vb2RfY3NfbGFnX3JlYyA9IGxlYWQocG9zX21vb2RfY3MsIG49MSwgb3JkZXJfYnk9c3ViamVjdGNvZGUpLA0KICAgICAgICAgbmVnX21vb2RfY3NfbGFnX3JlYyA9IGxlYWQobmVnX21vb2RfY3MsIG49MSwgb3JkZXJfYnk9c3ViamVjdGNvZGUpLA0KICAgICAgICAgcmVjX21lbV9wb3NfbW9vZF9jX2xhZyA9IGxlYWQocmVjX21lbV9wb3NfbW9vZF9jLCBuPTEsIG9yZGVyX2J5PXN1YmplY3Rjb2RlKSwNCiAgICAgICAgIHJlY19tZW1fbmVnX21vb2RfY19sYWcgPSBsZWFkKHJlY19tZW1fbmVnX21vb2RfYywgbj0xLCBvcmRlcl9ieT1zdWJqZWN0Y29kZSksDQogICAgICAgICBwb3NfbW9vZF9jX2xhZ19yZWMgPSBsZWFkKHBvc19tb29kX2MsIG49MSwgb3JkZXJfYnk9c3ViamVjdGNvZGUpLA0KICAgICAgICAgbmVnX21vb2RfY19sYWdfcmVjID0gbGVhZChuZWdfbW9vZF9jLCBuPTEsIG9yZGVyX2J5PXN1YmplY3Rjb2RlKSkgJT4lIA0KICB1bmdyb3VwKCkNCiAgDQoNCmBgYA0KDQojIERlc2NyaXB0aXZlcyB7LX0NCg0KV2UgZmlyc3QgcGxvdCBzb21lIGdlbmVyYWwgcG9wdWxhdGlvbiBkZXNjcmlwdGl2ZXMsIGZvbGxvd2VkIGJ5IHNvbWUgZGVzY3JpcHRpdmVzIG9mIHRoZSBzY2FsZXMgd2UgdXNlIGluIHRoZSBFTUEgd2Vla3MgYW5kIGNvbXBsaWFuY2UgcmF0ZXMgZm9yIGJvdGggcG9zaXRpdmUgYW5kIG5lZ2F0aXZlIG1vb2QuDQoNCiMjIFBvcHVsYXRpb24gey0gLnRhYnNldH0NCg0KIyMjIERlbW9ncmFwaGljcyB7LX0NCmBgYHtyIGZpZy5oZWlnaHQ9MTIsIGZpZy53aWR0aD0xMn0NCiNDcmVhdGUgRGVzY3JpcHRpdmVzIFRhYmxlcw0Kc3VtbWFyeV90YWJsZSA9IGRmX21lZGFsX2NsZWFuICU+JSBkaXN0aW5jdChzdWJqZWN0Y29kZSwgLmtlZXBfYWxsID0gVFJVRSkgJT4lIGdyb3VwX2J5KGNvbmRpdGlvbikgJT4lIHN1bW1hcmlzZSgNCiAgJ04nID0gbigpLA0KICAnQWdlIFxuIE0gKy8tIFNEJyA9IHBhc3RlMChyb3VuZChtZWFuKGFnZSwgbmEucm0gPVQpLCAxKSwgJyArLy0gJyAsIHJvdW5kKHNkKGFnZSwgbmEucm0gPVQpLCAxKSksDQogICMnTkEgQWdlJyA9IHN1bShpcy5uYShhZ2UpKSwgDQogICclIEVkdWNhdGlvbiBMb3cnID0gbWVhbihlZHVjYXRpb24gPT0gMCwgbmEucm0gPSBUKSoxMDAsDQogICclIEVkdWNhdGlvbiBNaWRkbGUnID0gbWVhbihlZHVjYXRpb24gPT0gMSwgbmEucm0gPSBUKSoxMDAsDQogICclIEVkdWNhdGlvbiBIaWdoJyA9IG1lYW4oZWR1Y2F0aW9uID09IDIsIG5hLnJtID0gVCkqMTAwLA0KICAjJ05BIEVkdWNhdGlvbicgPSBzdW0oaXMubmEoZWR1Y2F0aW9uKSksIA0KICAnJSBGZW1hbGUnID0gbWVhbihnZW5kZXIgPT0xLCBuYS5ybSA9IFQpKjEwMCwNCiAgIydOQSBHZW5kZXInID0gc3VtKGlzLm5hKGdlbmRlcikpDQopDQoNCiNDb21wbGlhbmNlIHJhdGVzDQpkZl9tZWRhbF9jb21wbGlhbmNlX2luZGl2aWR1YWwgPSBkZl9tZWRhbF9jbGVhbiAlPiUgZ3JvdXBfYnkoY29uZGl0aW9uLCBzdWJqZWN0Y29kZSkgJT4lIHN1bW1hcmlzZSgnQ29tcGxpYW5jZVJhdGUnID0gc3VtKCFpcy5uYSh0cmlnZ2VyX251bWJlcikpLzQyKjEwMCkNCg0KbGVuZ3RoKHdoaWNoKGRmX21lZGFsX2NvbXBsaWFuY2VfaW5kaXZpZHVhbCRDb21wbGlhbmNlUmF0ZSA8NzApKQ0KDQpkZl9tZWRhbF9jb21wbGlhbmNlID0gZGZfbWVkYWxfY2xlYW4gJT4lIGdyb3VwX2J5KGNvbmRpdGlvbikgJT4lIHN1bW1hcmlzZSgnJSBNZWFuIENvbXBsaWFuY2UnID0gc3VtKCFpcy5uYSh0cmlnZ2VyX251bWJlcikpLyhuX2Rpc3RpbmN0KHN1YmplY3Rjb2RlKSAqNDIpKjEwMCkgDQoNCg0KIyBDcmVhdGUgYSB0YWJsZQ0Kc3VtbWFyeV90YWJsZSA9IHN1bW1hcnlfdGFibGUgJT4lIGxlZnRfam9pbihkZl9tZWRhbF9jb21wbGlhbmNlLCBieSA9ICdjb25kaXRpb24nKQ0KcmVtcHN5Yzo6bmljZV90YWJsZShzdW1tYXJ5X3RhYmxlKQ0KYGBgDQoNCiMjIyBUZXN0cyB7LX0NCmBgYHtyfQ0KI2NyZWF0ZSBkYXRhc2V0IHdpdGggb25seSB1bmlxdWUgc3ViamVjdGNvZGUgDQpkZl9tZWRhbF9kaXN0aW5jdCA9IGRmX21lZGFsX2NsZWFuICU+JSBkaXN0aW5jdChzdWJqZWN0Y29kZSwgLmtlZXBfYWxsID0gVFJVRSklPiUgc2VsZWN0KCdzdWJqZWN0Y29kZScsICdjb25kaXRpb24nLCAnYWdlJywgJ2VkdWNhdGlvbicsICdnZW5kZXInKQ0KDQojVGVzdCBmb3IgZGlmZmVyZW5jZXMgYmV0d2VlbiBncm91cHMgDQogICNBZ2UNCiAgZGZfbWVkYWxfZGlzdGluY3QgJT4lIGxtKGFnZSB+IGNvbmRpdGlvbiwgZGF0YT0uKSAlPiUgc3VtbWFyeSgpDQogIA0KICAjZWR1Y2F0aW9uDQogIGNoaXNxLnRlc3QoZGZfbWVkYWxfZGlzdGluY3QkZWR1Y2F0aW9uLCBkZl9tZWRhbF9kaXN0aW5jdCRjb25kaXRpb24pDQogIA0KICAjZ2VuZGVyDQogIGNoaXNxLnRlc3QoZGZfbWVkYWxfZGlzdGluY3QkZ2VuZGVyLCBkZl9tZWRhbF9kaXN0aW5jdCRjb25kaXRpb24pDQpgYGANCg0KIyMjIFBsb3Qgey19DQpgYGB7cn0NCiNDcmVhdGUgYSBHcmFwaCAgDQogICNhZ2UNCiAgYm94cGxvdF9hZ2UgPC0gZ2dwbG90KGRmX21lZGFsX2Rpc3RpbmN0LCBhZXMoeD1jb25kaXRpb24sIHk9YWdlLCBmaWxsPWNvbmRpdGlvbikpICsNCiAgICBnZW9tX2JveHBsb3QoKSArDQogICAgbGFicyh4ID0gJ0NvbmRpdGlvbicsIHkgPSAnQWdlJywgdGFnID0gJ0MnICkgKw0KICAgIGdndGl0bGUoJ0FnZSBwZXIgQ29uZGl0aW9uJykgKw0KICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZShuPTMsIG5hbWU9J0dyYW5kQnVkYXBlc3QyJyApKSAgKw0KICAgIHRoZW1lX2FwYSgpIA0KICBnZ3Bsb3RseShib3hwbG90X2FnZSkNCiAgICANCiAgICAjZWR1Y2F0aW9uDQogICAgcGxvdF9lZHVjIDwtIGdncGxvdChkZl9tZWRhbF9kaXN0aW5jdCwgYWVzKHg9Y29uZGl0aW9uLCBmaWxsID0gZWR1Y2F0aW9uKSkgKw0KICAgICAgZ2VvbV9iYXIocG9zaXRpb24gPSAnZG9kZ2UnKSArDQogICAgICBsYWJzKHg9J0NvbmRpdGlvbicsIHk9ICdQcm9wb3J0aW9uJywgdGFnID0gJ0EnICkgKw0KICAgICAgZ2d0aXRsZSgnRWR1Y2F0aW9uIExldmVsIHBlciBDb25kaXRpb24nKSArDQogICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUobj0zLCBuYW1lPSdHcmFuZEJ1ZGFwZXN0MicgKSwgbGFiZWxzID0gYygnTG93JyAsICdNaWRkbGUnICwgJ0hpZ2gnKSwgbmFtZSA9ICdFZHVjYXRpb24nKSAgKw0KICAgICAgdGhlbWVfYXBhKCkgDQogICAgZ2dwbG90bHkocGxvdF9lZHVjKQ0KICAgICAgDQogICAgI0dlbmRlcg0KICAgIHBsb3RfZ2VuZGVyIDwtIGdncGxvdChkZl9tZWRhbF9kaXN0aW5jdCwgYWVzKHg9Y29uZGl0aW9uLCBmaWxsID0gZ2VuZGVyKSkgKw0KICAgICAgZ2VvbV9iYXIocG9zaXRpb24gPSAnZG9kZ2UnKSArDQogICAgICBsYWJzKHggPSAnQ29uZGl0aW9uJywgeSA9ICdQcm9wb3J0aW9uJywgdGFnID0gJ0InICkgKw0KICAgICAgZ2d0aXRsZSgnR2VuZGVyIHBlciBDb25kaXRpb24nKSArDQogICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSB3ZXNhbmRlcnNvbjo6d2VzX3BhbGV0dGUobj0zLCBuYW1lPSdHcmFuZEJ1ZGFwZXN0MicgKSwgbGFiZWxzID0gYygnTWFsZScsICdGZW1hbGUnKSwgJ0dlbmRlcicpICArDQogICAgICB0aGVtZV9hcGEoKSANCiAgICBnZ3Bsb3RseShwbG90X2dlbmRlcikNCiAgICAgIA0KICAgICBwbG90X2dlbmRlcl8yIDwtICBnZ3N0YXRzcGxvdDo6Z2diYXJzdGF0cyhkYXRhID0gZGZfbWVkYWxfZGlzdGluY3QsIHggPSBnZW5kZXIsIHkgPSBjb25kaXRpb24pICsNCiAgICAgICAgbGFicyh4ID0gJ0NvbmRpdGlvbicsIHkgPSAnUHJvcG9ydGlvbicsIHRhZyA9ICdCJyApICsNCiAgICAgICAgZ2d0aXRsZSgnR2VuZGVyIHBlciBDb25kaXRpb24nKSArDQogICAgICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHdlc2FuZGVyc29uOjp3ZXNfcGFsZXR0ZShuPTMsIG5hbWU9J0dyYW5kQnVkYXBlc3QyJyApLCBsYWJlbHMgPSBjKCdNYWxlJywgJ0ZlbWFsZScpLCAnR2VuZGVyJykgICsNCiAgICAgICAgdGhlbWVfYXBhKCkgDQogICAgICBnZ3Bsb3RseShwbG90X2dlbmRlcl8yKQ0KDQpnZ3B1YnI6OmdnYXJyYW5nZShwbG90X2VkdWMsIHBsb3RfZ2VuZGVyLCBib3hwbG90X2FnZSwgbnJvdz0yLCBuY29sPTIpICAgIA0KDQojIFN1YnNldCBieSBjb21wbGlhbmNlIHJhdGVzDQpjb21wbGlhbnRfc3VicyA9IGRmX21lZGFsX2NvbXBsaWFuY2VfaW5kaXZpZHVhbCAlPiUgZmlsdGVyKENvbXBsaWFuY2VSYXRlID49IDYwKSANCmRmX21lZGFsX2NsZWFuID0gZGZfbWVkYWxfY2xlYW5bZGZfbWVkYWxfY2xlYW4kc3ViamVjdGNvZGUgJWluJSBjb21wbGlhbnRfc3VicyRzdWJqZWN0Y29kZSAsXQ0KICAgIA0KYGBgDQoNCiMjIFBvc2l0aXZlIE1vb2QgIHsudGFic2V0IC19DQoNCiMjIyBDdXJyZW50IE1vb2Qgey19DQpgYGB7cn0NCmRlc2NyaWJlLmJ5KGRmX21lZGFsX2NsZWFuJHBvc19tb29kLCBncm91cD1kZl9tZWRhbF9jbGVhbiRjb25kaXRpb24pICU+JSByYmluZGxpc3QoKSAlPiUgbXV0YXRlKHZhcnM9YygiY29udCIsICJyZW0iLCAiZGVwIikpDQpgYGANCg0KRGlzdHJpYnV0aW9uDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGE9IGRmX21lZGFsX2NsZWFuLCBhZXMoeD1wb3NfbW9vZCkpICsgZ2VvbV9oaXN0b2dyYW0oKStmYWNldF9ncmlkKGNvbHM9dmFycyhjb25kaXRpb24pKQ0KYGBgIA0KDQpDZW50cmVkIERpc3RyaWJ1dGlvbiANCmBgYHtyfQ0KZ2dwbG90KGRhdGE9IGRmX21lZGFsX2NsZWFuLCBhZXMoeD1wb3NfbW9vZF9jKSkgKyBnZW9tX2hpc3RvZ3JhbSgpK2ZhY2V0X2dyaWQoY29scz12YXJzKGNvbmRpdGlvbikpDQpgYGANCg0KDQojIyMgUmVjZW50IE1lbW9yeSB7LX0NCg0KYGBge3J9DQpkZXNjcmliZS5ieShkZl9tZWRhbF9jbGVhbiRyZWNfbWVtX3Bvc19tb29kLCBncm91cD1kZl9tZWRhbF9jbGVhbiRjb25kaXRpb24pICU+JSByYmluZGxpc3QoKSAlPiUgbXV0YXRlKHZhcnM9YygiY29udCIsICJyZW0iLCAiZGVwIikpDQpgYGANCg0KRGlzdHJpYnV0aW9uDQpgYGB7cn0NCmdncGxvdChkYXRhPSBkZl9tZWRhbF9jbGVhbiwgYWVzKHg9cmVjX21lbV9wb3NfbW9vZCkpICsgZ2VvbV9oaXN0b2dyYW0oKStmYWNldF9ncmlkKGNvbHM9dmFycyhjb25kaXRpb24pKQ0KYGBgDQoNCkNlbnRyZWQgRGlzdHJpYnV0aW9uIA0KYGBge3J9DQpnZ3Bsb3QoZGF0YT0gZGZfbWVkYWxfY2xlYW4sIGFlcyh4PXJlY19tZW1fcG9zX21vb2RfYykpICsgZ2VvbV9oaXN0b2dyYW0oKStmYWNldF9ncmlkKGNvbHM9dmFycyhjb25kaXRpb24pKQ0KYGBgDQoNCg0KIyMjIFJlbW90ZSBNZW1vcnkgey19DQoNCmBgYHtyfQ0KZGVzY3JpYmUuYnkoZGZfbWVkYWxfY2xlYW4kcmVtX21lbV9wb3NfbW9vZCwgZ3JvdXA9ZGZfbWVkYWxfY2xlYW4kY29uZGl0aW9uKSAlPiUgcmJpbmRsaXN0KCkgJT4lIG11dGF0ZSh2YXJzPWMoImNvbnQiLCAicmVtIiwgImRlcCIpKQ0KYGBgDQoNCkRpc3RyaWJ1dGlvbg0KDQpgYGB7cn0NCmdncGxvdChkYXRhPSBkZl9tZWRhbF9jbGVhbiwgYWVzKHg9cmVtX21lbV9wb3NfbW9vZCkpICsgZ2VvbV9oaXN0b2dyYW0oKStmYWNldF9ncmlkKGNvbHM9dmFycyhjb25kaXRpb24pKQ0KYGBgDQoNCkNlbnRyZWQgRGlzdHJpYnV0aW9uIA0KYGBge3J9DQpnZ3Bsb3QoZGF0YT0gZGZfbWVkYWxfY2xlYW4sIGFlcyh4PXJlbV9tZW1fcG9zX21vb2RfYykpICsgZ2VvbV9oaXN0b2dyYW0oKStmYWNldF9ncmlkKGNvbHM9dmFycyhjb25kaXRpb24pKQ0KYGBgDQoNCg0KIyMgTmVnYXRpdmUgTW9vZCB7LSAudGFic2V0fQ0KDQojIyMgQ3VycmVudCBNb29kIHstfQ0KYGBge3J9DQpkZXNjcmliZS5ieShkZl9tZWRhbF9jbGVhbiRuZWdfbW9vZCwgZ3JvdXA9ZGZfbWVkYWxfY2xlYW4kY29uZGl0aW9uKSU+JSByYmluZGxpc3QoKSAlPiUgbXV0YXRlKHZhcnM9YygiY29udCIsICJyZW0iLCAiZGVwIikpDQoNCmBgYA0KDQpEaXN0cmlidXRpb24NCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YT0gZGZfbWVkYWxfY2xlYW4sIGFlcyh4PW5lZ19tb29kKSkgKyBnZW9tX2hpc3RvZ3JhbSgpK2ZhY2V0X2dyaWQoY29scz12YXJzKGNvbmRpdGlvbikpDQpgYGANCkNlbnRyZWQgRGlzdHJpYnV0aW9uIA0KYGBge3J9DQpnZ3Bsb3QoZGF0YT0gZGZfbWVkYWxfY2xlYW4sIGFlcyh4PW5lZ19tb29kX2MpKSArIGdlb21faGlzdG9ncmFtKCkrZmFjZXRfZ3JpZChjb2xzPXZhcnMoY29uZGl0aW9uKSkNCmdncGxvdChkYXRhPSBkZl9tZWRhbF9jbGVhbiwgYWVzKHg9bmVnX21vb2RfY3MpKSArIGdlb21faGlzdG9ncmFtKCkrZmFjZXRfZ3JpZChjb2xzPXZhcnMoY29uZGl0aW9uKSkNCmBgYA0KDQoNCiMjIyBSZWNlbnQgTWVtb3J5IHstfQ0KDQpgYGB7cn0NCmRlc2NyaWJlLmJ5KGRmX21lZGFsX2NsZWFuJHJlY19tZW1fbmVnX21vb2QsIGdyb3VwPWRmX21lZGFsX2NsZWFuJGNvbmRpdGlvbikgJT4lIHJiaW5kbGlzdCgpICU+JSBtdXRhdGUodmFycz1jKCJjb250IiwgInJlbSIsICJkZXAiKSkNCmBgYA0KDQpEaXN0cmlidXRpb24NCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YT0gZGZfbWVkYWxfY2xlYW4sIGFlcyh4PXJlY19tZW1fbmVnX21vb2QpKSArIGdlb21faGlzdG9ncmFtKCkrZmFjZXRfZ3JpZChjb2xzPXZhcnMoY29uZGl0aW9uKSkNCmBgYA0KQ2VudHJlZCBEaXN0cmlidXRpb24gDQpgYGB7cn0NCmdncGxvdChkYXRhPSBkZl9tZWRhbF9jbGVhbiwgYWVzKHg9cmVjX21lbV9uZWdfbW9vZF9jKSkgKyBnZW9tX2hpc3RvZ3JhbSgpK2ZhY2V0X2dyaWQoY29scz12YXJzKGNvbmRpdGlvbikpDQpgYGANCg0KDQojIyMgUmVtb3RlIE1lbW9yeSB7LX0NCg0KYGBge3J9DQpkZXNjcmliZS5ieShkZl9tZWRhbF9jbGVhbiRyZW1fbWVtX25lZ19tb29kLCBncm91cD1kZl9tZWRhbF9jbGVhbiRjb25kaXRpb24pICU+JSByYmluZGxpc3QoKSAlPiUgbXV0YXRlKHZhcnM9YygiY29udCIsICJyZW0iLCAiZGVwIikpDQpgYGANCg0KRGlzdHJpYnV0aW9uDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGE9IGRmX21lZGFsX2NsZWFuLCBhZXMoeD1yZW1fbWVtX25lZ19tb29kKSkgKyBnZW9tX2hpc3RvZ3JhbSgpK2ZhY2V0X2dyaWQoY29scz12YXJzKGNvbmRpdGlvbikpDQpgYGANCkNlbnRyZWQgRGlzdHJpYnV0aW9uIA0KYGBge3J9DQpnZ3Bsb3QoZGF0YT0gZGZfbWVkYWxfY2xlYW4sIGFlcyh4PXJlbV9tZW1fbmVnX21vb2RfYykpICsgZ2VvbV9oaXN0b2dyYW0oKStmYWNldF9ncmlkKGNvbHM9dmFycyhjb25kaXRpb24pKQ0KYGBgDQoNCg0KIyBNYWluIEVmZmVjdHMgey50YWJzZXR9DQpBIHNpbXBsZSBsaW5lYXIgcmVncmVzc2lvbiBhbmFseXNpcyB3YXMgZG9uZSB0byBsb29rIGF0IHRoZSBkaWZmZXJlbmNlcyBpbiBwb3NpdGl2ZSBhbmQgbmVnYXRpdmUgbW9vZCByYXRpbmdzIHBlciBjb25kaXRpb24uDQoNCiMjIExpbmVhciBNaXhlZCBNb2RlbHMgZm9yIFBBIGFuZCBOQQ0KYGBge3J9DQojcG9zaXRpdmUgbW9vZCANCnBvc2l0aXZlX21vZGVsID0gbG1lcihwb3NfbW9vZCB+IGNvbmRpdGlvbiArICgxfHN1YmplY3Rjb2RlKSwgZGF0YSA9IGRmX21lZGFsX2NsZWFuKQ0KDQoNCiNuZWdhdGl2ZSBtb29kDQpuZWdhdGl2ZV9tb2RlbCA9IGxtZXIobmVnX21vb2QgfiBjb25kaXRpb24gKyAoMXxzdWJqZWN0Y29kZSksIGRhdGEgPSBkZl9tZWRhbF9jbGVhbikNCg0KDQoNCmFzaXNfb3V0cHV0KHRhYl9tb2RlbCAocG9zaXRpdmVfbW9kZWwsIG5lZ2F0aXZlX21vZGVsLCANCiAgICAgICAgICAgICAgICAgICAgICBzaG93LnNlID0gVCwgc2hvdy5kZiA9IFQsIHNob3cuYWljID0gVCwgdHJhbnNmb3JtID0gTlVMTCwgIA0KICAgICAgICAgICAgICAgICAgICAgIHNob3cuc3RhdCA9IFQsIHNob3cuc3RkID0gVCwgDQogICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSAnQ29uZGl0aW9uIERpZmZlcmVuY2VzIE1vb2QgUmF0aW5nJywgZHYubGFiZWxzID0gYygnUEEgU2NhbGVkJywgICdOQSBTY2FsZWQnKSApJGtuaXRyKQ0KYGBgDQoNCiMjIFBsb3Qgey19DQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KDQojY3JlYXRlIGJveHBsb3QgZm9yIG5lZ2F0aXZlIGFuZCBwb3NpdGl2ZSBhZmZlY3QgZm9yIGVhY2ggZ3JvdXAgd2l0aCBzaWduaWZpY2FuY2UgbGV2ZWxzIA0KY29tYmluZV9kYXRhID0gZGZfbWVkYWxfY2xlYW4gJT4lDQogIHRpZHlyOjpwaXZvdF9sb25nZXIoY29scz1jKHBvc19tb29kLCBuZWdfbW9vZCksIG5hbWVzX3RvID0gJ21vb2RfdHlwZScsIHZhbHVlc190byA9ICdtb29kX3JhdGluZycpICU+JSANCiAgZHBseXI6Om11dGF0ZShtb29kX3R5cGUgPSBmYWN0b3IobW9vZF90eXBlLCBsZXZlbHMgPSBjKCdwb3NfbW9vZCcgLCAnbmVnX21vb2QnKSkpDQoNCiMgUGxvdA0KbG1fcGxvdCA9IGdncGxvdChjb21iaW5lX2RhdGEsIGFlcyh4PWNvbmRpdGlvbiwgeSA9IG1vb2RfcmF0aW5nLCBmaWxsPSBjb25kaXRpb24pKSArIA0KICBnZW9tX2JveHBsb3QoKSArDQogIGxhYnMoeCA9J0dyb3VwJywgeSA9J01vb2QgKHNjYWxlZCB1bml0cyknICkgKw0KICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGMoJ2NvbnRyb2wnID0gJ05ldmVyIERlcHJlc3NlZCcsICdyZW1pdHRlZCcgPSAnUmVtaXR0ZWQnLCAnZGVwcmVzc2VkJyA9ICdEZXByZXNzZWQnICkpICsNCiAgZmFjZXRfd3JhcCggfiBtb29kX3R5cGUsIG5jb2wgPTMsIG5yb3cgPSAyLCBsYWJlbGxlciAgPSBsYWJlbGxlcihtb29kX3R5cGUgPSBjKCdwb3NfbW9vZCcgPSAnUG9zaXRpdmUgTW9vZCcsICduZWdfbW9vZCcgID0gJ05lZ2F0aXZlIE1vb2QnKSkpICsNCiAgZ2VvbV9zaWduaWYoY29tcGFyaXNvbnMgPSBsaXN0KGMoJ2NvbnRyb2wnLCAncmVtaXR0ZWQnKSwgYygnY29udHJvbCcgLCAnZGVwcmVzc2VkJyksIGMoJ3JlbWl0dGVkJyAsICdkZXByZXNzZWQnICkpLCBtYXBfc2lnbmlmX2xldmVsID0gVCwgeV9wb3NpdGlvbiA9IGMoMTUsIDEzLCAxMSkpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gd2VzYW5kZXJzb246Ondlc19wYWxldHRlKG49MywgbmFtZT0nR3JhbmRCdWRhcGVzdDInICkpICArDQogIHRoZW1lX2FwYSgpICsgDQogIGd1aWRlcyhmaWxsPUYpDQpnZ3Bsb3RseShsbV9wbG90KQ0KZ2dzYXZlKCdmaWd1cmVfMV9tYWluX2VmZmVjdHMucGRmJywgZHBpID0gMzIwLCB3aWR0aCA9IDEyLCBoZWlnaHQgPSA4LCBwYXRoID0gImZpZ3VyZXMvIikNCmBgYA0KDQojIyBGb2xsb3ctVXAgey19DQpgYGB7cn0NCmVtbWVhbnM6OmVtbWVhbnMocG9zaXRpdmVfbW9kZWwsIHBhaXJ3aXNlIH4gY29uZGl0aW9uLCBwYmtydGVzdC5saW1pdCA9IDc4MDAsIGxtZXJUZXN0LmxpbWl0PTc4MDApDQplbW1lYW5zOjplbW1lYW5zKG5lZ2F0aXZlX21vZGVsLCBwYWlyd2lzZSB+IGNvbmRpdGlvbiwgcGJrcnRlc3QubGltaXQgPSA3ODAwLCBsbWVyVGVzdC5saW1pdD03ODAwKQ0KYGBgDQoNCg0KDQojIEh5cG90aGVzaXMgMTogSW5kZXBlbmRlbnQgTW9kZWxzICANCg0KSW4gdGhpcyBzZWN0aW9uIHdlIHRlc3QgdGhlIGZpcnN0IG1vZGVscyBmcm9tIGh5cG90aGVzaXMgMSBhcyBzdGF0ZWQgaW4gdGhlIHByZS1yZWdpc3RyYWl0b24uIFRoZXNlIGFuYWx5c2VzIGxvb2sgYXQgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHJlY2VudCBhbmQgcmVtb3RlIGVtb3Rpb25hbCBtZW1vcnkgZm9yIGJvdGggcG9zaXRpdmUgYW5kIG5lZ2F0aXZlIGFmZmVjdCwgd2hpbGUgYWxzbyBsb29raW5nIGF0IGdyb3VwIGRpZmZlcmVuY2VzIGluIHRoZXNlIHJlbGFpdG9uc2hpcHMgYmFzZWQgb24gZGVwcmVzc2lvbiBzdGF0dXMuIA0KDQpgYGB7cn0NCiMgc2V0IG1vZGVsIGZhbWlsaWVzDQptb2RlbF9mYW1pbGllcyA9IGMoJ2dhdXNzLWxpbmsnLCAiZ2F1c3MtbG9nIiwgJ2dhdXNzLWludicsICdHYW1tYS1saW5rJywgJ0dhbW1hLWxvZycpDQojIGRldGVjdCBjb3JlcyBmb3IgbGF0ZXINCm5jb3JlcyA9IGRldGVjdENvcmVzKCktMQ0KYGBgDQoNCiMjIFBvc2l0aXZlIEFmZmVjdCB7LSAudGFic2V0fQ0KDQpGaXJzdCB3ZSBydW4gdGhlIHBvc2l0aXZlIGFmZmVjdCBtb2RlbHMuIEZvciBlYWNoIG9mIHRoZSByZWNlbnQgYW5kIHJlbW90ZSBtb2RlbHMsIHdlIGNoZWNrIHRoZSBiZXN0IGZpdHRpbmcgbW9kZWwgYXMgc3RhdGVkIGluIHRoZSBwcmUtcmVnaXN0cmF0aW9uIGJhc2VkIG9uIHRoZSBBSUMgYW5kIHRoZSByZXNpZHVhbHMuIFdlIHRoZW4gY2hlY2sgd2hldGhlciBtZWRpYXRpb24gYW5hbHlzZXMgYXJlIHdhcnJhbnRlZCwgYW5kIHJ1biB0aG9zZS4gV2l0aGluIGVhY2ggdGFiIGJlbG93LCB3ZSBwcmVzZW50IHRoZSByZXN1bHRzIGFuZCBzdGVwcyB0YWtlbiwgYXMgd2VsbCBhcyBwb3N0LWhvYyBhbmFseXNlcyB0byBleGFtaW5lIHRoZSBkaXJlY3Rpb25hbGl0eSBvZiB0aGUgZWZmZWN0cy4gDQoNCiMjIyBSZWNlbnQgey0gfQ0KYGBge3J9DQojIE1vZGVsIGVxdWF0aW9uDQpoMV9wb3N0X3JlY2VudF9lcSA9ICJwb3NfbW9vZF9jcyB+IDEgKyBjb25kaXRpb24qcmVjX21lbV9wb3NfbW9vZF9jc19sYWcgKyBnZW5kZXIgKyBhZ2UgKyBlZHVjYXRpb24gKyAoMSArIHJlY19tZW1fcG9zX21vb2RfY3NfbGFnfHN1YmplY3Rjb2RlKSINCg0KIyBzZXQgY2x1c3RlcnMNCmNsID0gbWFrZUNsdXN0ZXIobmNvcmVzKQ0KcmVnaXN0ZXJEb1BhcmFsbGVsKGNsKQ0KDQojIHJ1biBwYXJhbGxlbA0KaDFfcG9zX3JlY2VudF9tb2RlbHMgPSBmb3JlYWNoKGZhbWlseSA9IG1vZGVsX2ZhbWlsaWVzLCAuY29tYmluZSA9ICdjJywgLnBhY2thZ2VzID0gYygnbG1lclRlc3QnKSwgLmVycm9yaGFuZGxpbmcgPSAicmVtb3ZlIikgJWRvcGFyJSB7DQogIGZpdF9hbGxfbW9kcyhoMV9wb3N0X3JlY2VudF9lcSwgZGZfbWVkYWxfY2xlYW4sIGZhbWlseSkgfQ0Kc3RvcENsdXN0ZXIoY2wpDQoNCiMgcHJpbnQgdGhlIG1vZGVscyBpbnRvIGEgc2luZ2xlIHRhYmxlDQphc2lzX291dHB1dCggdGFiX21vZGVsKGgxX3Bvc19yZWNlbnRfbW9kZWxzLCAgZHYubGFiZWxzID0gbmFtZXMoaDFfcG9zX3JlY2VudF9tb2RlbHMpLCANCiAgICAgICAgICAgICAgICAgICAgICAgc2hvdy5pY2MgPSBULCBzaG93LmFpYyA9IFQsIHRyYW5zZm9ybSA9IE5VTEwsIHNob3cuc2UgPSBULCBkaWdpdHMgPSAzKSRrbml0cikNCmBgYA0KDQpgYGB7cn0NCnN1bW1hcnkoaDFfcG9zX3JlY2VudF9tb2RlbHNbWzJdXSkNCnBsb3RfZGlhZ25vc3RpY3MoaDFfcG9zX3JlY2VudF9tb2RlbHMpDQpjYXI6OnZpZihoMV9wb3NfcmVjZW50X21vZGVsc1tbMl1dKSAjVmlmcyB3ZXJlIGluc3BlY3RlZCB3aXRob3V0IGludGVyYWN0aW9uIGFuZCBkZWVtZWQgT0sNCmBgYA0KDQojIyMjIyBGb2xsb3ctdXAgey19DQoNCkluIHRoZSBmb2xsb3ctdXAgd2UgbG9vayBhdCB0aGUgcGFpcndpc2UgZGlmZmVyZW5jZXMgaW4gdGhlIHNsb3BlcywgYW5kIHRoZSBpbmRpaXZ1ZHMNCmBgYHtyfQ0KZW1tZWFuczo6ZW10cmVuZHMoaDFfcG9zX3JlY2VudF9tb2RlbHNbWzJdXSwgcGFpcndpc2UgfiBjb25kaXRpb24sIHZhcj0ncmVjX21lbV9wb3NfbW9vZF9jc19sYWcnLCBsbWVyVGVzdC5saW1pdCA9IDM1MDAsIHBia3J0ZXN0LmxpbWl0ID0gMzUwMCApDQpgYGANCg0KYGBge3J9DQojY3JlYXRlIHNlcGFyYXRlIGRhdGFmcmFtZXMgDQpkZl9tZWRhbF9jbGVhbl9jb250cm9sID0gZGZfbWVkYWxfY2xlYW4gJT4lIGZpbHRlcihjb25kaXRpb24gPT0gJ2NvbnRyb2wnKQ0KZGZfbWVkYWxfY2xlYW5fcmVtaXR0ZWQgPSBkZl9tZWRhbF9jbGVhbiAlPiUgZmlsdGVyKGNvbmRpdGlvbiA9PSAncmVtaXR0ZWQnKQ0KZGZfbWVkYWxfY2xlYW5fZGVwcmVzc2VkID0gZGZfbWVkYWxfY2xlYW4gJT4lIGZpbHRlcihjb25kaXRpb24gPT0gJ2RlcHJlc3NlZCcpIA0KDQoNCm0xX3Bvc19yZWNfY29udHJvbCA8LSAgIGxtZXIocG9zX21vb2RfY3MgfiByZWNfbWVtX3Bvc19tb29kX2NzX2xhZyArIGdlbmRlciArIGFnZSArIGVkdWNhdGlvbiANCiAgICAgICAgICAgICAgICAgICAgICsgKDEgICsgIHJlY19tZW1fcG9zX21vb2RfY3NfbGFnfHN1YmplY3Rjb2RlKSwgDQogICAgICAgICAgICAgICAgICAgZGF0YT1kZl9tZWRhbF9jbGVhbl9jb250cm9sLA0KICAgICAgICAgICAgICAgICAgIGNvbnRyb2wgPSBsbWVyQ29udHJvbChjYWxjLmRlcml2cyA9IEYsIG9wdGltaXplcj0nYm9ieXFhJywgb3B0Q3RybD1saXN0KG1heGZ1bj0xZTYpKSkNCg0KbTFfcG9zX3JlY19yZW1pdHRlZCA8LSAgIGxtZXIocG9zX21vb2RfY3MgfiByZWNfbWVtX3Bvc19tb29kX2NzX2xhZyArIGdlbmRlciArIGFnZSArIGVkdWNhdGlvbiANCiAgICAgICAgICAgICAgICAgICAgICsgKDEgKyByZWNfbWVtX3Bvc19tb29kX2NzX2xhZ3xzdWJqZWN0Y29kZSksIA0KICAgICAgICAgICAgICAgICAgIGRhdGE9ZGZfbWVkYWxfY2xlYW5fcmVtaXR0ZWQsDQogICAgICAgICAgICAgICAgICAgY29udHJvbCA9IGxtZXJDb250cm9sKGNhbGMuZGVyaXZzID0gRiwgb3B0aW1pemVyPSdib2J5cWEnLCBvcHRDdHJsPWxpc3QobWF4ZnVuPTFlNikpKQ0KDQptMV9wb3NfcmVjX2RlcHJlc3NlZCA8LSAgIGxtZXIocG9zX21vb2RfY3MgfiByZWNfbWVtX3Bvc19tb29kX2NzX2xhZyArIGdlbmRlciArIGFnZSArIGVkdWNhdGlvbiANCiAgICAgICAgICAgICAgICAgICAgICsgKDEgICsgcmVjX21lbV9wb3NfbW9vZF9jc19sYWd8c3ViamVjdGNvZGUpLCANCiAgICAgICAgICAgICAgICAgICBkYXRhPWRmX21lZGFsX2NsZWFuX2RlcHJlc3NlZCwNCiAgICAgICAgICAgICAgICAgICBjb250cm9sID0gbG1lckNvbnRyb2woY2FsYy5kZXJpdnMgPSBGLCBvcHRpbWl6ZXI9J2JvYnlxYScsIG9wdEN0cmw9bGlzdChtYXhmdW49MWU2KSkpDQoNCmFzaXNfb3V0cHV0KHRhYl9tb2RlbChtMV9wb3NfcmVjX2NvbnRyb2wsIG0xX3Bvc19yZWNfcmVtaXR0ZWQsIG0xX3Bvc19yZWNfZGVwcmVzc2VkLCBzaG93LnNlID0gVCwgc2hvdy5haWMgPSBULCB0cmFuc2Zvcm0gPSBOVUxMLCBkdi5sYWJlbHMgPSBjKCdjb250cm9sJywgJ3JlbWl0dGVkJywgJ2RlcHJlc3NlZCcpKSRrbml0cikgDQpgYGANCg0KDQojIyMgUmVtb3RlIHstfQ0KYGBge3J9DQojIE1vZGVsIGVxdWF0aW9uDQpoMV9wb3NfcmVtb3RlX2VxID0gInBvc19tb29kX2NzIH4gMSArICBjb25kaXRpb24qcmVtX21lbV9wb3NfbW9vZF9jc19sYWcgKyBnZW5kZXIgKyBhZ2UgKyBlZHVjYXRpb24gKyAoMSAgKyByZW1fbWVtX3Bvc19tb29kX2NzX2xhZ3xzdWJqZWN0Y29kZSkiDQoNCiMgc2V0IGNsdXN0ZXJzDQpjbCA9IG1ha2VDbHVzdGVyKG5jb3JlcykNCnJlZ2lzdGVyRG9QYXJhbGxlbChjbCkNCg0KIyBydW4gcGFyYWxsZWwNCmgxX3Bvc19yZW1vdGVfbW9kZWxzID0gZm9yZWFjaChmYW1pbHkgPSBtb2RlbF9mYW1pbGllcywgLmNvbWJpbmUgPSAnYycsIC5wYWNrYWdlcyA9IGMoJ2xtZXJUZXN0JyksICAuZXJyb3JoYW5kbGluZyA9ICJyZW1vdmUiKSAlZG9wYXIlIHsNCiAgZml0X2FsbF9tb2RzKGgxX3Bvc19yZW1vdGVfZXEsIGRmX21lZGFsX2NsZWFuLCBmYW1pbHkpIH0NCnN0b3BDbHVzdGVyKGNsKQ0KDQojIHByaW50IHRoZSBtb2RlbHMgaW50byBhIHNpbmdsZSB0YWJsZQ0KYXNpc19vdXRwdXQoIHRhYl9tb2RlbChoMV9wb3NfcmVtb3RlX21vZGVscywgZHYubGFiZWxzID0gbmFtZXMoaDFfcG9zX3JlbW90ZV9tb2RlbHMpLCANCiAgICAgICAgICAgICAgICAgICAgICAgc2hvdy5pY2MgPSBULCBzaG93LmFpYyA9IFQsIHRyYW5zZm9ybSA9IE5VTEwsIHNob3cuc2UgPSBULCBkaWdpdHMgPSAzKSRrbml0cikNCmBgYA0KDQpgYGB7cn0NCnN1bW1hcnkoaDFfcG9zX3JlbW90ZV9tb2RlbHNbWzJdXSkNCnBsb3RfZGlhZ25vc3RpY3MoaDFfcG9zX3JlbW90ZV9tb2RlbHMpDQpjYXI6OnZpZihoMV9wb3NfcmVtb3RlX21vZGVsc1tbMl1dKSAjVklGcyB3aXRob3V0IGludGVyYWN0aW9ucyB3ZXJlIGZpbmUNCmBgYA0KDQoNCiMjIyMjIEZvbGxvdy11cCB7LX0NCmBgYHtyfQ0KZW1tZWFuczo6ZW10cmVuZHMoaDFfcG9zX3JlbW90ZV9tb2RlbHNbWzRdXSwgcGFpcndpc2UgfiBjb25kaXRpb24sIHZhcj0ncmVtX21lbV9wb3NfbW9vZF9jc19sYWcnICkNCg0KYGBgDQoNCg0KYGBge3J9DQoNCm0xX3Bvc19yZW1fY29udHJvbCA8LSBsbWVyKHBvc19tb29kX2NzIH4gMSArIHJlbV9tZW1fcG9zX21vb2RfY3NfbGFnICsgZ2VuZGVyICsgYWdlICsgZWR1Y2F0aW9uICsgKDEgICsgcmVtX21lbV9wb3NfbW9vZF9jc19sYWd8c3ViamVjdGNvZGUpLCANCiAgICAgICAgICAgICAgICAgICAgIGRhdGE9ZGZfbWVkYWxfY2xlYW5fY29udHJvbCwNCiAgICAgICAgICAgICAgICAgICAgY29udHJvbCA9IGxtZXJDb250cm9sKGNhbGMuZGVyaXZzID0gRiwgb3B0aW1pemVyPSdib2J5cWEnLCBvcHRDdHJsPWxpc3QobWF4ZnVuPTFlNikpKQ0KDQptMV9wb3NfcmVtX3JlbWl0dGVkIDwtIGxtZXIocG9zX21vb2RfY3MgfiAxICsgcmVtX21lbV9wb3NfbW9vZF9jc19sYWcgKyBnZW5kZXIgKyBhZ2UgKyBlZHVjYXRpb24gKyAoMSAgKyByZW1fbWVtX3Bvc19tb29kX2NzX2xhZ3xzdWJqZWN0Y29kZSksIA0KICAgICAgICAgICAgICAgICAgICAgZGF0YT1kZl9tZWRhbF9jbGVhbl9yZW1pdHRlZCwNCiAgICAgICAgICAgICAgICAgICAgIGNvbnRyb2wgPSBsbWVyQ29udHJvbChjYWxjLmRlcml2cyA9IEYsIG9wdGltaXplcj0nYm9ieXFhJywgb3B0Q3RybD1saXN0KG1heGZ1bj0xZTYpKSkNCg0KbTFfcG9zX3JlbV9kZXByZXNzZWQgPC0gbG1lcihwb3NfbW9vZF9jcyB+IDEgKyByZW1fbWVtX3Bvc19tb29kX2NzX2xhZyArIGdlbmRlciArIGFnZSArIGVkdWNhdGlvbiArICgxICArIHJlbV9tZW1fcG9zX21vb2RfY3NfbGFnfHN1YmplY3Rjb2RlKSwgDQogICAgICAgICAgICAgICAgICAgICAgIGRhdGE9ZGZfbWVkYWxfY2xlYW5fZGVwcmVzc2VkLA0KICAgICAgICAgICAgICAgICAgICAgICBjb250cm9sID0gbG1lckNvbnRyb2woY2FsYy5kZXJpdnMgPSBGLCBvcHRpbWl6ZXI9J2JvYnlxYScsIG9wdEN0cmw9bGlzdChtYXhmdW49MWU2KSkpDQoNCmFzaXNfb3V0cHV0KHRhYl9tb2RlbChtMV9wb3NfcmVtX2NvbnRyb2wsIG0xX3Bvc19yZW1fcmVtaXR0ZWQsIG0xX3Bvc19yZW1fZGVwcmVzc2VkLCBzaG93LnNlID0gVCwgc2hvdy5haWMgPSBULCB0cmFuc2Zvcm0gPSBOVUxMLCBkdi5sYWJlbHMgPSBjKCdjb250cm9sJywgJ3JlbWl0dGVkJywgJ2RlcHJlc3NlZCcpKSRrbml0cikgDQoNCmBgYA0KDQoNCg0KDQojIyBOZWdhdGl2ZSBBZmZlY3Qgey0gLnRhYnNldH0NCg0KV2UgbmV4dCBydW4gdGhlIG5lZ2F0aXZlIGFmZmVjdCBtb2RlbHMuIEZvciBlYWNoIG9mIHRoZSByZWNlbnQgYW5kIHJlbW90ZSBtb2RlbHMsIHdlIGNoZWNrIHRoZSBiZXN0IGZpdHRpbmcgbW9kZWwgYXMgc3RhdGVkIGluIHRoZSBwcmUtcmVnaXN0cmF0aW9uIGJhc2VkIG9uIHRoZSBBSUMgYW5kIHRoZSByZXNpZHVhbHMuIFdlIHRoZW4gY2hlY2sgd2hldGhlciBtZWRpYXRpb24gYW5hbHlzZXMgYXJlIHdhcnJhbnRlZCwgYW5kIHJ1biB0aG9zZS4gV2l0aGluIGVhY2ggdGFiIGJlbG93LCB3ZSBwcmVzZW50IHRoZSByZXN1bHRzIGFuZCBzdGVwcyB0YWtlbiwgYXMgd2VsbCBhcyBwb3N0LWhvYyBhbmFseXNlcyB0byBleGFtaW5lIHRoZSBkaXJlY3Rpb25hbGl0eSBvZiB0aGUgZWZmZWN0cw0KDQojIyMgUmVjZW50IHstfQ0KYGBge3J9DQojIE1vZGVsIGVxdWF0aW9uDQpoMV9uZWdfcmVjZW50X2VxID0gIm5lZ19tb29kX2NzIH4gY29uZGl0aW9uKnJlY19tZW1fbmVnX21vb2RfY3NfbGFnICArIGdlbmRlciArIGFnZSArIGVkdWNhdGlvbiArICgxICsgcmVjX21lbV9uZWdfbW9vZF9jc19sYWcgfCBzdWJqZWN0Y29kZSkiDQojIHNldCBjbHVzdGVycw0KY2wgPSBtYWtlQ2x1c3RlcihuY29yZXMpDQpyZWdpc3RlckRvUGFyYWxsZWwoY2wpDQoNCiMgcnVuIHBhcmFsbGVsDQpoMV9uZWdfcmVjZW50X21vZGVscyA9IGZvcmVhY2goZmFtaWx5ID0gbW9kZWxfZmFtaWxpZXMsIC5jb21iaW5lID0gJ2MnLCAucGFja2FnZXMgPSBjKCdsbWVyVGVzdCcpLCAuZXJyb3JoYW5kbGluZyA9ICdyZW1vdmUnKSAlZG9wYXIlIHsNCiAgZml0X2FsbF9tb2RzKGgxX25lZ19yZWNlbnRfZXEsIGRmX21lZGFsX2NsZWFuLCBmYW1pbHkpIH0NCnN0b3BDbHVzdGVyKGNsKQ0KDQojIHByaW50IHRoZSBtb2RlbHMgaW50byBhIHNpbmdsZSB0YWJsZQ0KYXNpc19vdXRwdXQoIHRhYl9tb2RlbChoMV9uZWdfcmVjZW50X21vZGVscywgIGR2LmxhYmVscyA9IG5hbWVzKGgxX25lZ19yZWNlbnRfbW9kZWxzKSwgDQogICAgICAgICAgICAgICAgICAgICAgIHNob3cuaWNjID0gVCwgc2hvdy5haWMgPSBULCB0cmFuc2Zvcm0gPSBOVUxMLCBzaG93LnNlID0gVCwgZGlnaXRzID0gMykka25pdHIpDQoNCmBgYA0KDQoNCmBgYHtyfQ0Kc3VtbWFyeShoMV9uZWdfcmVjZW50X21vZGVsc1tbNF1dKQ0KcGxvdF9kaWFnbm9zdGljcyhoMV9uZWdfcmVjZW50X21vZGVscykNCmNhcjo6dmlmKGgxX25lZ19yZWNlbnRfbW9kZWxzW1s0XV0pDQpgYGANCg0KDQoNCiMjIyMgRm9sbG93LXVwIHstfQ0KYGBge3J9DQplbW1lYW5zOjplbXRyZW5kcyhoMV9uZWdfcmVjZW50X21vZGVsc1tbNF1dLCBwYWlyd2lzZSB+IGNvbmRpdGlvbiwgdmFyPSdyZWNfbWVtX25lZ19tb29kX2NzX2xhZycgKQ0KDQplbW1lYW5zOjplbW1lYW5zKGgxX25lZ19yZWNlbnRfbW9kZWxzW1s0XV0sIGlkZW50aXR5IH4gcmVjX21lbV9uZWdfbW9vZF9jc19sYWcgfCBjb25kaXRpb24gKQ0KYGBgDQoNCg0KYGBge3J9DQoNCm0xX25lZ19yZWNfY29udHJvbCA8LSBnbG1lcihuZWdfbW9vZF9jcyB+IDEgKyByZWNfbWVtX25lZ19tb29kX2NzX2xhZyArIGdlbmRlciArIGFnZSArIGVkdWNhdGlvbiArICgwICArIHJlY19tZW1fbmVnX21vb2RfY3NfbGFnfHN1YmplY3Rjb2RlKSwgDQogICAgICAgICAgICAgICAgICAgZGF0YT1kZl9tZWRhbF9jbGVhbl9jb250cm9sLA0KICAgICAgICAgICAgICAgICAgIGZhbWlseSA9IEdhbW1hKGxpbms9aWRlbnRpdHkpLA0KICAgICAgICAgICAgICAgICAgIGNvbnRyb2wgPSBnbG1lckNvbnRyb2woY2FsYy5kZXJpdnMgPSBGLCBvcHRpbWl6ZXI9J2JvYnlxYScsIG9wdEN0cmw9bGlzdChtYXhmdW49MWU2KSkpDQoNCm0xX25lZ19yZWNfcmVtaXR0ZWQgPC1nbG1lcihuZWdfbW9vZF9jcyB+IDEgKyByZWNfbWVtX25lZ19tb29kX2NzX2xhZyArIGdlbmRlciArIGFnZSArIGVkdWNhdGlvbiArICgwICArIHJlY19tZW1fbmVnX21vb2RfY3NfbGFnfHN1YmplY3Rjb2RlKSwgDQogICAgICAgICAgICAgICAgICAgZGF0YT1kZl9tZWRhbF9jbGVhbl9yZW1pdHRlZCwNCiAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSBHYW1tYShsaW5rPWlkZW50aXR5KSwNCiAgICAgICAgICAgICAgICAgICBjb250cm9sID0gZ2xtZXJDb250cm9sKGNhbGMuZGVyaXZzID0gRiwgb3B0aW1pemVyPSdib2J5cWEnLCBvcHRDdHJsPWxpc3QobWF4ZnVuPTFlNikpKQ0KDQptMV9uZWdfcmVjX2RlcHJlc3NlZCA8LWdsbWVyKG5lZ19tb29kX2NzIH4gMSArIHJlY19tZW1fbmVnX21vb2RfY3NfbGFnICsgZ2VuZGVyICsgYWdlICsgZWR1Y2F0aW9uICsgKDAgICsgcmVjX21lbV9uZWdfbW9vZF9jc19sYWd8c3ViamVjdGNvZGUpLCANCiAgICAgICAgICAgICAgICAgICBkYXRhPWRmX21lZGFsX2NsZWFuX2RlcHJlc3NlZCwNCiAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSBHYW1tYShsaW5rPWlkZW50aXR5KSwNCiAgICAgICAgICAgICAgICAgICBjb250cm9sID0gZ2xtZXJDb250cm9sKGNhbGMuZGVyaXZzID0gRiwgb3B0aW1pemVyPSdib2J5cWEnLCBvcHRDdHJsPWxpc3QobWF4ZnVuPTFlNikpKQ0KDQphc2lzX291dHB1dCh0YWJfbW9kZWwobTFfbmVnX3JlY19jb250cm9sLCBtMV9uZWdfcmVjX3JlbWl0dGVkLCBtMV9uZWdfcmVjX2RlcHJlc3NlZCwgc2hvdy5zZSA9IFQsIHNob3cuYWljID0gVCwgdHJhbnNmb3JtID0gTlVMTCwgZHYubGFiZWxzID0gYygnY29udHJvbCcsICdyZW1pdHRlZCcsICdkZXByZXNzZWQnKSkka25pdHIpIA0KYGBgDQoNCiMjIyBSZW1vdGUgey19DQpgYGB7cn0NCiMgTW9kZWwgZXF1YXRpb24NCmgxX25lZ19yZW1vdGVfZXEgPSAibmVnX21vb2RfY3MgfiBjb25kaXRpb24qcmVtX21lbV9uZWdfbW9vZF9jc19sYWcgICsgZ2VuZGVyICsgYWdlICsgZWR1Y2F0aW9uICsgKDAgICsgcmVtX21lbV9uZWdfbW9vZF9jc19sYWd8c3ViamVjdGNvZGUpIg0KDQojIHNldCBjbHVzdGVycw0KY2wgPSBtYWtlQ2x1c3RlcihuY29yZXMpDQpyZWdpc3RlckRvUGFyYWxsZWwoY2wpDQoNCiMgcnVuIHBhcmFsbGVsDQpoMV9uZWdfcmVtb3RlX21vZGVscyA9IGZvcmVhY2goZmFtaWx5ID0gbW9kZWxfZmFtaWxpZXMsIC5jb21iaW5lID0gJ2MnLCAucGFja2FnZXMgPSBjKCdsbWVyVGVzdCcpLCAgLmVycm9yaGFuZGxpbmcgPSAicmVtb3ZlIikgJWRvcGFyJSB7DQogIGZpdF9hbGxfbW9kcyhoMV9uZWdfcmVtb3RlX2VxLCBkZl9tZWRhbF9jbGVhbiwgZmFtaWx5KSB9DQpzdG9wQ2x1c3RlcihjbCkNCg0KIyBwcmludCB0aGUgbW9kZWxzIGludG8gYSBzaW5nbGUgdGFibGUNCmFzaXNfb3V0cHV0KCB0YWJfbW9kZWwoaDFfbmVnX3JlbW90ZV9tb2RlbHMsICAgZHYubGFiZWxzID0gbmFtZXMoaDFfbmVnX3JlbW90ZV9tb2RlbHMpLCANCiAgICAgICAgICAgICAgICAgICAgICAgc2hvdy5pY2MgPSBULCBzaG93LmFpYyA9IFQsIHRyYW5zZm9ybSA9IE5VTEwsIHNob3cuc2UgPSBULCBkaWdpdHMgPSAzKSRrbml0cikNCg0KYGBgDQoNCg0KYGBge3J9DQpzdW1tYXJ5KGgxX25lZ19yZW1vdGVfbW9kZWxzW1syXV0pDQpwbG90X2RpYWdub3N0aWNzKGgxX25lZ19yZW1vdGVfbW9kZWxzKQ0KY2FyOjp2aWYoaDFfbmVnX3JlbW90ZV9tb2RlbHNbWzJdXSkNCmBgYA0KDQoNCiMjIyMgRm9sbG93LXVwIHstfQ0KYGBge3J9DQplbW1lYW5zOjplbXRyZW5kcyhoMV9uZWdfcmVtb3RlX21vZGVsc1tbMl1dLCBwYWlyd2lzZSB+IGNvbmRpdGlvbiwgdmFyPSdyZW1fbWVtX25lZ19tb29kX2NzX2xhZycgKQ0KDQpgYGANCg0KYGBge3J9DQoNCm0xX25lZ19yZW1fY29udHJvbCA8LSAgZ2xtZXIobmVnX21vb2RfY3MgfiAxICsgcmVtX21lbV9uZWdfbW9vZF9jc19sYWcgKyBnZW5kZXIgKyBhZ2UgKyBlZHVjYXRpb24gKyAoMCAgKyByZW1fbWVtX25lZ19tb29kX2NzX2xhZ3xzdWJqZWN0Y29kZSksIA0KICAgICAgICAgICAgICAgICAgIGRhdGE9ZGZfbWVkYWxfY2xlYW5fY29udHJvbCwNCiAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSBHYW1tYShsaW5rPWlkZW50aXR5KSwNCiAgICAgICAgICAgICAgICAgICBjb250cm9sID0gZ2xtZXJDb250cm9sKGNhbGMuZGVyaXZzID0gRiwgb3B0aW1pemVyPSdib2J5cWEnLCBvcHRDdHJsPWxpc3QobWF4ZnVuPTFlNikpKQ0KDQptMV9uZWdfcmVtX3JlbWl0dGVkIDwtIGdsbWVyKG5lZ19tb29kX2NzIH4gMSArIHJlbV9tZW1fbmVnX21vb2RfY3NfbGFnICsgZ2VuZGVyICsgYWdlICsgZWR1Y2F0aW9uICsgKDAgICsgcmVtX21lbV9uZWdfbW9vZF9jc19sYWd8c3ViamVjdGNvZGUpLA0KICAgICAgICAgICAgICAgICAgIGRhdGE9ZGZfbWVkYWxfY2xlYW5fcmVtaXR0ZWQsDQogICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gR2FtbWEobGluaz1pZGVudGl0eSksDQogICAgICAgICAgICAgICAgICAgY29udHJvbCA9IGdsbWVyQ29udHJvbChjYWxjLmRlcml2cyA9IEYsIG9wdGltaXplcj0nYm9ieXFhJywgb3B0Q3RybD1saXN0KG1heGZ1bj0xZTYpKSkNCg0KbTFfbmVnX3JlbV9kZXByZXNzZWQgPC0gIGdsbWVyKG5lZ19tb29kX2NzIH4gMSArIHJlbV9tZW1fbmVnX21vb2RfY3NfbGFnICsgZ2VuZGVyICsgYWdlICsgZWR1Y2F0aW9uICsgKDAgICsgcmVtX21lbV9uZWdfbW9vZF9jc19sYWd8c3ViamVjdGNvZGUpLA0KICAgICAgICAgICAgICAgICAgIGRhdGE9ZGZfbWVkYWxfY2xlYW5fZGVwcmVzc2VkLA0KICAgICAgICAgICAgICAgICAgIGZhbWlseSA9IEdhbW1hKGxpbms9aWRlbnRpdHkpLA0KICAgICAgICAgICAgICAgICAgIGNvbnRyb2wgPSBnbG1lckNvbnRyb2woY2FsYy5kZXJpdnMgPSBGLCBvcHRpbWl6ZXI9J2JvYnlxYScsIG9wdEN0cmw9bGlzdChtYXhmdW49MWU2KSkpDQoNCmFzaXNfb3V0cHV0KHRhYl9tb2RlbChtMV9uZWdfcmVtX2NvbnRyb2wsIG0xX25lZ19yZW1fcmVtaXR0ZWQsIG0xX25lZ19yZW1fZGVwcmVzc2VkLCBzaG93LnNlID0gVCwgc2hvdy5haWMgPSBULCB0cmFuc2Zvcm0gPSBOVUxMLCBkdi5sYWJlbHMgPSBjKCdjb250cm9sJywgJ3JlbWl0dGVkJywgJ2RlcHJlc3NlZCcpKSRrbml0cikgDQpgYGANCg0KDQoNCiMgSHlwb3RoZXNpcyAyOiBDdXJyZW50IEFmZmVjdCBNb2RlcmF0aW9uIA0KDQpGb3IgSDIsIHdlIHdhbnQgdG8gc2VlIHdoZXRoZXIgY3VycmVudCBhZmZlY3RpdmUgc3RhdGVzIG1vZGVyYXRlIHRoZSBhYmlsaXR5IHRvIHJlY2FsbCBwcmV2aW91cyBhZmZlY3RpdmUgc3RhdGVzLiBUaGF0IGlzLCBkbyBjdXJyZW50IG5lZ2F0aXZlIGFmZmVjdCBmZWVsaW5ncyBtb2RlcmF0ZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gYWZmZWN0IGFuZCByZWNhbGw/IA0KDQpgYGB7cn0NCiNjcmVhdGUgc2VwYXJhdGUgZGF0YWZyYW1lcyBmb3IgZWFjaCBncm91cA0KZGZfbWVkYWxfY2xlYW5fY29udHJvbCA9IGRmX21lZGFsX2NsZWFuICU+JSBmaWx0ZXIoY29uZGl0aW9uPT0nY29udHJvbCcpDQpkZl9tZWRhbF9jbGVhbl9yZW1pdHRlZCA9IGRmX21lZGFsX2NsZWFuICU+JSBmaWx0ZXIoY29uZGl0aW9uPT0ncmVtaXR0ZWQnKQ0KZGZfbWVkYWxfY2xlYW5fZGVwcmVzc2VkID0gZGZfbWVkYWxfY2xlYW4gJT4lIGZpbHRlcihjb25kaXRpb249PSdkZXByZXNzZWQnKQ0KDQojY3JlYXRlIGEgbmV3IGRhdGFmcmFtZSBmb3IgdGhlIHJlbW90ZSB2YXJpYWJsZXMsIHdoZXJlIHRoZSBwYXJ0aWNpcGFudHMgd2l0aCB0aGUgc2luZ3VsYXIgZGF0YXBvaW50cyBhcmUgcmVtb3ZlZCANCmRmX21lZGFsX2NsZWFuX3JlbW90ZSA9IGRmX21lZGFsX2NsZWFuICU+JSBmaWx0ZXIgKCEoc3ViamVjdGNvZGUgPT0gODIyIHwgc3ViamVjdGNvZGUgPT0gOTA2IHwgc3ViamVjdGNvZGUgPT0gNzE3KSkNCg0KI2NyZWF0ZSBzZXBhcmF0ZSBkYXRhZnJhbWVzIHBlciBjb25kaXRpb24gDQpkZl9tZWRhbF9jbGVhbl9yZW1vdGVfY29udHJvbCA9IGRmX21lZGFsX2NsZWFuX3JlbW90ZSAlPiUgZmlsdGVyKGNvbmRpdGlvbj09J2NvbnRyb2wnKQ0KZGZfbWVkYWxfY2xlYW5fcmVtb3RlX3JlbWl0dGVkID0gZGZfbWVkYWxfY2xlYW5fcmVtb3RlICU+JSBmaWx0ZXIoY29uZGl0aW9uPT0ncmVtaXR0ZWQnKQ0KZGZfbWVkYWxfY2xlYW5fcmVtb3RlX2RlcHJlc3NlZCA9IGRmX21lZGFsX2NsZWFuX3JlbW90ZSAlPiUgZmlsdGVyKGNvbmRpdGlvbj09J2RlcHJlc3NlZCcpDQpgYGANCg0KIyMgUG9zaXRpdmUgQWZmZWN0IHstIC50YWJzZXR9DQoNCiMjIyBSZWNlbnQgey19DQpBbiBsbWVyIG1vZGVsIHdhcyBmaXR0ZWQgd2l0aCBnYXVzc2lhbiBpZGVudGl0eSwgbG9nICYgaW52ZXJzZSBhcyB3ZWxsIGFzIEdhbW1hIGxvZywgaW52ZXJzZSwgYW5kIGlkZW50aXR5LiBUaGUgbW9kZWxzLCBob3dldmVyLCB3ZXJlIG5vdCBhIGdvb2QgZml0IGFuZCB0aGUgZ2F1c3NpYW4gaWRlbnRpdHkgbW9kZWwgY29wZWQgd2l0aCBzaW5ndWxhcml0eS4gSGVuY2UsIGEgbm9ybWFsIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIHdhcyBmaXR0ZWQuIA0KYGBge3IgZmlnLmhlaWdodD0yMCwgZmlnLndpZHRoPTE1fQ0KaDJfcG9zX3JlY2VudF9lcSA9ICJwb3NfbW9vZF9jcyB+IGNvbmRpdGlvbipyZWNfbWVtX3Bvc19tb29kX2NzX2xhZypwb3NfbW9vZF9jc19sYWdfcmVjICsgZ2VuZGVyICsgYWdlICsgZWR1Y2F0aW9uICsgKDEgKyByZWNfbWVtX3Bvc19tb29kX2NzX2xhZyArIHBvc19tb29kX2NzX2xhZ19yZWN8c3ViamVjdGNvZGUpIg0KDQojIHNldCBjbHVzdGVycw0KY2wgPSBtYWtlQ2x1c3RlcihuY29yZXMpDQpyZWdpc3RlckRvUGFyYWxsZWwoY2wpDQoNCiMgcnVuIHBhcmFsbGVsDQpoMl9wb3NfcmVjZW50X21vZGVscyA9IGZvcmVhY2goZmFtaWx5ID0gbW9kZWxfZmFtaWxpZXMsIC5jb21iaW5lID0gJ2MnLCAucGFja2FnZXMgPSBjKCdsbWVyVGVzdCcpLCAgLmVycm9yaGFuZGxpbmcgPSAicmVtb3ZlIikgJWRvcGFyJSB7DQogIGZpdF9hbGxfbW9kcyhoMl9wb3NfcmVjZW50X2VxLCBkZl9tZWRhbF9jbGVhbiwgZmFtaWx5KSB9DQpzdG9wQ2x1c3RlcihjbCkNCg0KIyBwcmludCB0aGUgbW9kZWxzIGludG8gYSBzaW5nbGUgdGFibGUNCmFzaXNfb3V0cHV0KCB0YWJfbW9kZWwoaDJfcG9zX3JlY2VudF9tb2RlbHMsICBkdi5sYWJlbHMgPSBuYW1lcyhoMl9wb3NfcmVjZW50X21vZGVscyksIA0KICAgICAgICAgICAgICAgICAgICAgICBzaG93LmljYyA9IFQsIHNob3cuYWljID0gVCwgdHJhbnNmb3JtID0gTlVMTCwgc2hvdy5zZSA9IFQsIGRpZ2l0cyA9IDMpJGtuaXRyKQ0KDQoNCmBgYA0KDQpEdWUgdG8gc2luZ3VsYXJpdHkgdGhpcyB3YXMgZGV0ZXJtaW5lZCB0byBiZSB0aGUgYmVzdCBmaXQgZm9yIHRoZSBtb2RkZWwNCg0KYGBge3J9DQpzdW1tYXJ5KGgyX3Bvc19yZWNlbnRfbW9kZWxzW1syXV0pDQpwbG90X2RpYWdub3N0aWNzKGgyX3Bvc19yZWNlbnRfbW9kZWxzKQ0KY2FyOjp2aWYoaDJfcG9zX3JlY2VudF9tb2RlbHNbWzJdXSkNCmBgYA0KDQoNCg0KIyMjIyBGb2xsb3ctdXAgey19DQpgYGB7cn0NCm0yX3Bvc19yZWNfY29udHJvbCA8LSBsbShwb3NfbW9vZF9jcyB+IDEgKyByZWNfbWVtX3Bvc19tb29kX2NzX2xhZypwb3NfbW9vZF9jc19sYWdfcmVjICsgZ2VuZGVyICsgYWdlICsgZWR1Y2F0aW9uLA0KICAgICAgICAgICAgICAgICAgIGRhdGE9ZGZfbWVkYWxfY2xlYW5fY29udHJvbCkNCg0KbTJfcG9zX3JlY19yZW1pdHRlZCA8LSBsbShwb3NfbW9vZF9jcyB+IDEgKyByZWNfbWVtX3Bvc19tb29kX2NzX2xhZypwb3NfbW9vZF9jc19sYWdfcmVjICsgZ2VuZGVyICsgYWdlICsgZWR1Y2F0aW9uLA0KICAgICAgICAgICAgICAgICAgIGRhdGE9ZGZfbWVkYWxfY2xlYW5fcmVtaXR0ZWQpDQoNCm0yX3Bvc19yZWNfZGVwcmVzc2VkIDwtICBsbShwb3NfbW9vZF9jcyB+IDEgKyByZWNfbWVtX3Bvc19tb29kX2NzX2xhZypwb3NfbW9vZF9jc19sYWdfcmVjICsgZ2VuZGVyICsgYWdlICsgZWR1Y2F0aW9uLA0KICAgICAgICAgICAgICAgICAgIGRhdGE9ZGZfbWVkYWxfY2xlYW5fZGVwcmVzc2VkKQ0KDQphc2lzX291dHB1dCh0YWJfbW9kZWwobTJfcG9zX3JlY19jb250cm9sLCBtMl9wb3NfcmVjX3JlbWl0dGVkLCBtMl9wb3NfcmVjX2RlcHJlc3NlZCwgc2hvdy5zZSA9IFQsIHNob3cuYWljID0gVCwgdHJhbnNmb3JtID0gTlVMTCwgZHYubGFiZWxzID0gYygnY29udHJvbCcsICdyZW1pdHRlZCcsICdkZXByZXNzZWQnKSkka25pdHIpDQpgYGANCg0KDQojIyMgUmVtb3RlIHstIC50YWJzZXR9DQoNCkFuIGxtZXIgbW9kZWwgd2FzIGZpdHRlZCB3aXRoIGdhdXNzaWFuIGlkZW50aXR5LCBsb2cgJiBpbnZlcnNlIGFzIHdlbGwgYXMgR2FtbWEgbG9nLCBpbnZlcnNlLCBhbmQgaWRlbnRpdHkuIFRoZSBtb2RlbHMsIGhvd2V2ZXIsIHdlcmUgbm90IGEgZ29vZCBmaXQgYW5kIHRoZSBnYXVzc2lhbiBpZGVudGl0eSBtb2RlbCBjb3BlZCB3aXRoIHNpbmd1bGFyaXR5LiBIZW5jZSwgYSBub3JtYWwgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgd2FzIGZpdHRlZC4gDQpgYGB7cn0NCmgyX3Bvc19yZW1vdGVfZXEgPSAicG9zX21vb2RfY3MgfiBjb25kaXRpb24qcmVtX21lbV9wb3NfbW9vZF9jc19sYWcqcG9zX21vb2RfY3NfbGFnX3JlbSArIGdlbmRlciArIGFnZSArIGVkdWNhdGlvbiArICgxIHwgc3ViamVjdGNvZGUpIg0KDQojIHNldCBjbHVzdGVycw0KY2wgPSBtYWtlQ2x1c3RlcihuY29yZXMpDQpyZWdpc3RlckRvUGFyYWxsZWwoY2wpDQoNCiMgcnVuIHBhcmFsbGVsDQpoMl9wb3NfcmVtb3RlX21vZGVscyA9IGZvcmVhY2goZmFtaWx5ID0gbW9kZWxfZmFtaWxpZXMsIC5jb21iaW5lID0gJ2MnLCAucGFja2FnZXMgPSBjKCdsbWVyVGVzdCcpLCAgLmVycm9yaGFuZGxpbmcgPSAicmVtb3ZlIikgJWRvcGFyJSB7DQogIGZpdF9hbGxfbW9kcyhoMl9wb3NfcmVtb3RlX2VxLCBkZl9tZWRhbF9jbGVhbiwgZmFtaWx5KSB9DQpzdG9wQ2x1c3RlcihjbCkNCg0KIyBwcmludCB0aGUgbW9kZWxzIGludG8gYSBzaW5nbGUgdGFibGUNCmFzaXNfb3V0cHV0KCB0YWJfbW9kZWwoaDJfcG9zX3JlbW90ZV9tb2RlbHMsICBkdi5sYWJlbHMgPSBuYW1lcyhoMl9wb3NfcmVtb3RlX21vZGVscyksIA0KICAgICAgICAgICAgICAgICAgICAgICBzaG93LmljYyA9IFQsIHNob3cuYWljID0gVCwgdHJhbnNmb3JtID0gTlVMTCwgc2hvdy5zZSA9IFQsIGRpZ2l0cyA9IDMpJGtuaXRyKQ0KDQoNCmBgYA0KDQoNCkR1ZSB0byBzaW5ndWxhcml0eSBhIHJlZ3VsYXIgbGluZWFyIG1vZGVsIHdhcyBmaXR0ZWQuDQpgYGB7cn0NCnN1bW1hcnkoaDJfcG9zX3JlbW90ZV9tb2RlbHNbWzJdXSkNCnBsb3RfZGlhZ25vc3RpY3MoaDJfcG9zX3JlbW90ZV9tb2RlbHMpDQpjYXI6OnZpZihoMl9wb3NfcmVtb3RlX21vZGVsc1tbMl1dKQ0KDQpgYGANCg0KDQojIyMjIEZvbGxvdy11cCB7LX0NCmBgYHtyfQ0KDQptMl9wb3NfcmVtX2NvbnRyb2wgPC0gbG0ocG9zX21vb2RfY3MgfiByZW1fbWVtX3Bvc19tb29kX2NzX2xhZypwb3NfbW9vZF9jc19sYWdfcmVtICArIGdlbmRlciArIGFnZSArIGVkdWNhdGlvbiwgDQogICAgICAgICAgICAgICAgICAgZGF0YT1kZl9tZWRhbF9jbGVhbl9yZW1vdGVfY29udHJvbCkNCg0KbTJfcG9zX3JlbV9yZW1pdHRlZCA8LSBsbShwb3NfbW9vZF9jcyB+IHJlbV9tZW1fcG9zX21vb2RfY3NfbGFnKnBvc19tb29kX2NzX2xhZ19yZW0gICsgZ2VuZGVyICsgYWdlICsgZWR1Y2F0aW9uLCAgDQogICAgICAgICAgICAgICAgICAgZGF0YT1kZl9tZWRhbF9jbGVhbl9yZW1vdGVfcmVtaXR0ZWQpDQoNCm0yX3Bvc19yZW1fZGVwcmVzc2VkIDwtICBsbShwb3NfbW9vZF9jcyB+IHJlbV9tZW1fcG9zX21vb2RfY3NfbGFnKnBvc19tb29kX2NzX2xhZ19yZW0gICsgZ2VuZGVyICsgYWdlICsgZWR1Y2F0aW9uLCANCiAgICAgICAgICAgICAgICAgICBkYXRhPWRmX21lZGFsX2NsZWFuX3JlbW90ZV9kZXByZXNzZWQpDQoNCmFzaXNfb3V0cHV0KHRhYl9tb2RlbChtMl9wb3NfcmVtX2NvbnRyb2wsIG0yX3Bvc19yZW1fcmVtaXR0ZWQsIG0yX3Bvc19yZW1fZGVwcmVzc2VkLCBzaG93LnNlID0gVCwgc2hvdy5haWMgPSBULCB0cmFuc2Zvcm0gPSBOVUxMLCBkdi5sYWJlbHMgPSBjKCdjb250cm9sJywgJ3JlbWl0dGVkJywgJ2RlcHJlc3NlZCcpKSRrbml0cikgDQpgYGANCg0KDQoNCiMjIE5lZ2F0aXZlIEFmZmVjdCB7LSAudGFic2V0fQ0KDQojIyMgIFJlY2VudCB7LX0NCmBgYHtyfQ0KaDJfbmVnX3JlY2VudF9lcSA9ICJuZWdfbW9vZF9jcyB+IGNvbmRpdGlvbipyZWNfbWVtX25lZ19tb29kX2NzX2xhZypuZWdfbW9vZF9jc19sYWdfcmVjICsgZ2VuZGVyICsgYWdlICsgZWR1Y2F0aW9uICsgKDEgKyByZWNfbWVtX25lZ19tb29kX2NzX2xhZyArIG5lZ19tb29kX2NzX2xhZ19yZWN8c3ViamVjdGNvZGUpIg0KDQojIHNldCBjbHVzdGVycw0KY2wgPSBtYWtlQ2x1c3RlcihuY29yZXMpDQpyZWdpc3RlckRvUGFyYWxsZWwoY2wpDQoNCiMgcnVuIHBhcmFsbGVsDQpoMl9uZWdfcmVjZW50X21vZGVscyA9IGZvcmVhY2goZmFtaWx5ID0gbW9kZWxfZmFtaWxpZXMsIC5jb21iaW5lID0gJ2MnLCAucGFja2FnZXMgPSBjKCdsbWVyVGVzdCcpLCAgLmVycm9yaGFuZGxpbmcgPSAicmVtb3ZlIikgJWRvcGFyJSB7DQogIGZpdF9hbGxfbW9kcyhoMl9uZWdfcmVjZW50X2VxLCBkZl9tZWRhbF9jbGVhbiwgZmFtaWx5KSB9DQpzdG9wQ2x1c3RlcihjbCkNCg0KIyBwcmludCB0aGUgbW9kZWxzIGludG8gYSBzaW5nbGUgdGFibGUNCmFzaXNfb3V0cHV0KCB0YWJfbW9kZWwoaDJfbmVnX3JlY2VudF9tb2RlbHMsIGR2LmxhYmVscyA9IG5hbWVzKGgyX25lZ19yZWNlbnRfbW9kZWxzKSwgDQogICAgICAgICAgICAgICAgICAgICAgIHNob3cuaWNjID0gVCwgc2hvdy5haWMgPSBULCB0cmFuc2Zvcm0gPSBOVUxMLCBzaG93LnNlID0gVCwgZGlnaXRzID0gMykka25pdHIpDQoNCmBgYA0KDQpDaGVjayBGaW5hbCBNb2RlbA0KYGBge3IgfQ0Kc3VtbWFyeShoMl9uZWdfcmVjZW50X21vZGVsc1tbNF1dKQ0KcGxvdF9kaWFnbm9zdGljcyhoMl9uZWdfcmVjZW50X21vZGVscykgDQpjYXI6OnZpZihoMl9uZWdfcmVjZW50X21vZGVsc1tbNF1dKQ0KDQpgYGANCg0KDQoNCg0KIyMjIyBGb2xsb3ctdXAgey19DQpgYGB7cn0NCg0KbTJfbmVnX3JlY19jb250cm9sIDwtIGdsbWVyKG5lZ19tb29kX2NzIH4gcmVjX21lbV9uZWdfbW9vZF9jc19sYWcqbmVnX21vb2RfY3NfbGFnX3JlYyArIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZGVyICsgYWdlICsgZWR1Y2F0aW9uICsgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoMSAgKyByZWNfbWVtX25lZ19tb29kX2NzX2xhZyB8IHN1YmplY3Rjb2RlKSArICgxICsgIG5lZ19tb29kX2NzX2xhZ19yZWN8c3ViamVjdGNvZGUpLCANCiAgICAgICAgICAgICAgICAgICBkYXRhPWRmX21lZGFsX2NsZWFuX2NvbnRyb2wsDQogICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gR2FtbWEobGluaz1pZGVudGl0eSksIA0KICAgICAgICAgICAgICAgICAgIGNvbnRyb2wgPSBnbG1lckNvbnRyb2woY2FsYy5kZXJpdnMgPSBGLCBvcHRpbWl6ZXI9J2JvYnlxYScsIG9wdEN0cmw9bGlzdChtYXhmdW49MWU2KSkpDQoNCm0yX25lZ19yZWNfcmVtaXR0ZWQgPC0gZ2xtZXIobmVnX21vb2RfY3MgfiByZWNfbWVtX25lZ19tb29kX2NzX2xhZypuZWdfbW9vZF9jc19sYWdfcmVjICsgZ2VuZGVyICsgYWdlICsgZWR1Y2F0aW9uICsgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoMSAgKyByZWNfbWVtX25lZ19tb29kX2NzX2xhZyB8IHN1YmplY3Rjb2RlKSArICgxICsgIG5lZ19tb29kX2NzX2xhZ19yZWN8c3ViamVjdGNvZGUpLCANCiAgICAgICAgICAgICAgICAgICBkYXRhPWRmX21lZGFsX2NsZWFuX3JlbWl0dGVkLA0KICAgICAgICAgICAgICAgICAgIGZhbWlseSA9IEdhbW1hKGxpbms9aWRlbnRpdHkpLCANCiAgICAgICAgICAgICAgICAgICBjb250cm9sID0gZ2xtZXJDb250cm9sKGNhbGMuZGVyaXZzID0gRiwgb3B0aW1pemVyPSdib2J5cWEnLCBvcHRDdHJsPWxpc3QobWF4ZnVuPTFlNikpKQ0KDQptMl9uZWdfcmVjX2RlcHJlc3NlZCA8LSAgZ2xtZXIobmVnX21vb2RfY3MgfiByZWNfbWVtX25lZ19tb29kX2NzX2xhZypuZWdfbW9vZF9jc19sYWdfcmVjICsgZ2VuZGVyICsgYWdlICsgZWR1Y2F0aW9uICsgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoMSAgKyByZWNfbWVtX25lZ19tb29kX2NzX2xhZyB8IHN1YmplY3Rjb2RlKSArICgxICsgIG5lZ19tb29kX2NzX2xhZ19yZWN8c3ViamVjdGNvZGUpLCAgDQogICAgICAgICAgICAgICAgICAgZGF0YT1kZl9tZWRhbF9jbGVhbl9kZXByZXNzZWQsDQogICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gR2FtbWEobGluaz1pZGVudGl0eSksIA0KICAgICAgICAgICAgICAgICAgIGNvbnRyb2wgPSBnbG1lckNvbnRyb2woY2FsYy5kZXJpdnMgPSBGLCBvcHRpbWl6ZXI9J2JvYnlxYScsIG9wdEN0cmw9bGlzdChtYXhmdW49MWU2KSkpDQoNCmFzaXNfb3V0cHV0KHRhYl9tb2RlbChtMl9uZWdfcmVjX2NvbnRyb2wsIG0yX25lZ19yZWNfcmVtaXR0ZWQsIG0yX25lZ19yZWNfZGVwcmVzc2VkLCBzaG93LnNlID0gVCwgc2hvdy5haWMgPSBULCB0cmFuc2Zvcm0gPSBOVUxMLCBkdi5sYWJlbHMgPSBjKCdjb250cm9sJywgJ3JlbWl0dGVkJywgJ2RlcHJlc3NlZCcpKSRrbml0cikgDQpgYGANCg0KDQoNCg0KIyMjIFJlbW90ZSB7LX0NCmBgYHtyfQ0KaDJfbmVnX3JlbW90ZV9lcSA9ICJuZWdfbW9vZF9jcyB+IGNvbmRpdGlvbipyZW1fbWVtX25lZ19tb29kX2NzX2xhZypuZWdfbW9vZF9jc19sYWdfcmVtICsgZ2VuZGVyICsgYWdlICsgZWR1Y2F0aW9uICsgKDEgKyByZW1fbWVtX25lZ19tb29kX2NzX2xhZyArIG5lZ19tb29kX2NzX2xhZ19yZW18c3ViamVjdGNvZGUpIg0KDQojIHNldCBjbHVzdGVycw0KY2wgPSBtYWtlQ2x1c3RlcihuY29yZXMpDQpyZWdpc3RlckRvUGFyYWxsZWwoY2wpDQoNCiMgcnVuIHBhcmFsbGVsDQpoMl9uZWdfcmVtb3RlX21vZGVscyA9IGZvcmVhY2goZmFtaWx5ID0gbW9kZWxfZmFtaWxpZXMsIC5jb21iaW5lID0gJ2MnLCAucGFja2FnZXMgPSBjKCdsbWVyVGVzdCcpLCAgLmVycm9yaGFuZGxpbmcgPSAicmVtb3ZlIikgJWRvcGFyJSB7DQogIGZpdF9hbGxfbW9kcyhoMl9uZWdfcmVtb3RlX2VxLCBkZl9tZWRhbF9jbGVhbiwgZmFtaWx5KSB9DQpzdG9wQ2x1c3RlcihjbCkNCg0KIyBwcmludCB0aGUgbW9kZWxzIGludG8gYSBzaW5nbGUgdGFibGUNCmFzaXNfb3V0cHV0KCB0YWJfbW9kZWwoaDJfbmVnX3JlbW90ZV9tb2RlbHMsIGR2LmxhYmVscyA9IG5hbWVzKGgyX25lZ19yZW1vdGVfbW9kZWxzKSwgDQogICAgICAgICAgICAgICAgICAgICAgIHNob3cuaWNjID0gVCwgc2hvdy5haWMgPSBULCB0cmFuc2Zvcm0gPSBOVUxMLCBzaG93LnNlID0gVCwgZGlnaXRzID0gMykka25pdHIpDQoNCmBgYA0KDQpDaGVjayBGaW5hbCBNb2RlbA0KYGBge3J9DQpzdW1tYXJ5KGgyX25lZ19yZW1vdGVfbW9kZWxzW1s0XV0pDQpwbG90X2RpYWdub3N0aWNzKGgyX25lZ19yZW1vdGVfbW9kZWxzKQ0KY2FyOjp2aWYoaDJfbmVnX3JlbW90ZV9tb2RlbHNbWzRdXSkNCmBgYA0KDQoNCg0KDQojIyMjIEZvbGxvdy11cCB7LX0NCmBgYHtyfQ0KDQptMl9uZWdfcmVtX2NvbnRyb2wgPC0gZ2xtZXIobmVnX21vb2RfY3MgfiByZW1fbWVtX25lZ19tb29kX2NzX2xhZypuZWdfbW9vZF9jc19sYWdfcmVtICArIGdlbmRlciArIGFnZSArIGVkdWNhdGlvbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICsgKDEgICsgIHJlbV9tZW1fbmVnX21vb2RfY3NfbGFnfHN1YmplY3Rjb2RlKSArICgxICsgbmVnX21vb2RfY3NfbGFnX3JlbXxzdWJqZWN0Y29kZSksIA0KICAgICAgICAgICAgICAgICAgIGRhdGE9ZGZfbWVkYWxfY2xlYW5fcmVtb3RlX2NvbnRyb2wsDQogICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gR2FtbWEobGluaz1pZGVudGl0eSksIA0KICAgICAgICAgICAgICAgICAgIGNvbnRyb2wgPSBnbG1lckNvbnRyb2woY2FsYy5kZXJpdnMgPSBGLCBvcHRpbWl6ZXI9J2JvYnlxYScsIG9wdEN0cmw9bGlzdChtYXhmdW49MWU2KSkpDQoNCm0yX25lZ19yZW1fcmVtaXR0ZWQgPC0gZ2xtZXIobmVnX21vb2RfY3MgfiByZW1fbWVtX25lZ19tb29kX2NzX2xhZypuZWdfbW9vZF9jc19sYWdfcmVtICArIGdlbmRlciArIGFnZSArIGVkdWNhdGlvbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICsgKDEgICsgIHJlbV9tZW1fbmVnX21vb2RfY3NfbGFnfHN1YmplY3Rjb2RlKSArICgxICsgbmVnX21vb2RfY3NfbGFnX3JlbXxzdWJqZWN0Y29kZSksDQogICAgICAgICAgICAgICAgICAgZGF0YT1kZl9tZWRhbF9jbGVhbl9yZW1vdGVfcmVtaXR0ZWQsDQogICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gR2FtbWEobGluaz1pZGVudGl0eSksIA0KICAgICAgICAgICAgICAgICAgIGNvbnRyb2wgPSBnbG1lckNvbnRyb2woY2FsYy5kZXJpdnMgPSBGLCBvcHRpbWl6ZXI9J2JvYnlxYScsIG9wdEN0cmw9bGlzdChtYXhmdW49MWU2KSkpDQoNCm0yX25lZ19yZW1fZGVwcmVzc2VkIDwtICBnbG1lcihuZWdfbW9vZF9jcyB+IHJlbV9tZW1fbmVnX21vb2RfY3NfbGFnKm5lZ19tb29kX2NzX2xhZ19yZW0gICsgZ2VuZGVyICsgYWdlICsgZWR1Y2F0aW9uDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgKyAoMSAgKyAgcmVtX21lbV9uZWdfbW9vZF9jc19sYWd8c3ViamVjdGNvZGUpICsgKDEgKyBuZWdfbW9vZF9jc19sYWdfcmVtfHN1YmplY3Rjb2RlKSwgDQogICAgICAgICAgICAgICAgICAgZGF0YT1kZl9tZWRhbF9jbGVhbl9yZW1vdGVfZGVwcmVzc2VkLA0KICAgICAgICAgICAgICAgICAgIGZhbWlseSA9IEdhbW1hKGxpbms9aWRlbnRpdHkpLCANCiAgICAgICAgICAgICAgICAgICBjb250cm9sID0gZ2xtZXJDb250cm9sKGNhbGMuZGVyaXZzID0gRiwgb3B0aW1pemVyPSdib2J5cWEnLCBvcHRDdHJsPWxpc3QobWF4ZnVuPTFlNikpKQ0KDQphc2lzX291dHB1dCh0YWJfbW9kZWwobTJfbmVnX3JlbV9jb250cm9sLCBtMl9uZWdfcmVtX3JlbWl0dGVkLCBtMl9uZWdfcmVtX2RlcHJlc3NlZCwgc2hvdy5zZSA9IFQsIHNob3cuYWljID0gVCwgdHJhbnNmb3JtID0gTlVMTCwgZHYubGFiZWxzID0gYygnY29udHJvbCcsICdyZW1pdHRlZCcsICdkZXByZXNzZWQnKSkka25pdHIpIA0KYGBgDQoNCg0KIyBFeHBsb3JhdG9yeSBBbmFseXNlcw0KDQojIyBNZWRpYXRpb24gTW9kZWxzIHsudGFic2V0fQ0KDQpGb2xsb3dpbmcgdGhlIHRlc3RzIHdlIHJhbiBmb3IgaHlwb3RoZXNpcyAxLCB3ZSB3b3VsZCBhbHNvIGxpa2UgdG8gc2VlIHdoZXRoZXIgb3Igbm90IG1lZGlhdGlvbiBlZmZlY3RzIGV4aXN0LiANCg0KIyMjIFJlY1BBIHstfQ0KDQpgYGB7cn0NCg0KI2NyZWF0ZSBhIG5ldyBkYXRhZnJhbWUgZm9yIHRoZSByZW1vdGUgdmFyaWFibGVzLCB3aGVyZSB0aGUgcGFydGljaXBhbnRzIHdpdGggdGhlIHNpbmd1bGFyIGRhdGFwb2ludHMgYXJlIHJlbW92ZWQgDQpkZl9tZWRhbF9tb2RlcmF0aW9uID0gIGRmX21lZGFsX2NsZWFuICU+JSANCiAgZmlsdGVyICghKHN1YmplY3Rjb2RlID09IDgyMiB8IHN1YmplY3Rjb2RlID09IDkwNiB8IHN1YmplY3Rjb2RlID09IDcxNykpICU+JSANCiAgZmlsdGVyKCEoaXMubmEocG9zX21vb2QpIHwgaXMubmEocmVjX21lbV9wb3NfbW9vZF9sYWcpKSkgDQoNCiMgbWVkIG1vZGVsDQptZWRfZml0X2gxX3Bvc19yZWMgPC0gbG1lNDo6bG1lcihyZWNfbWVtX3Bvc19tb29kX2xhZyB+IGNvbmRpdGlvbl9kdW1teSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSArIGdlbmRlciArIGVkdWNhdGlvbiArIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoMSB8c3ViamVjdGNvZGUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGRmX21lZGFsX21vZGVyYXRpb24pDQojIGZ1bGwgbW9kZWwNCm91dF9maXRfaDFfcG9zX3JlYyA8LWxtZTQ6OmxtZXIocG9zX21vb2QgfiBjb25kaXRpb25fZHVtbXkgKyByZWNfbWVtX3Bvc19tb29kX2xhZyArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWdlICsgZ2VuZGVyICtlZHVjYXRpb24gKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICgxICsgcmVjX21lbV9wb3NfbW9vZF9sYWcgfHN1YmplY3Rjb2RlKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBkZl9tZWRhbF9tb2RlcmF0aW9uKQ0KDQojbWVkaWF0aW9uIGFuYWx5c2lzIGZvciBjb250cm9sIGFuZCBkZXByZXNzZWQNCm1lZF9wb3NfcmVjX2RlcCA8LSBtZWRpYXRpb246Om1lZGlhdGUobWVkX2ZpdF9oMV9wb3NfcmVjLCBvdXRfZml0X2gxX3Bvc19yZWMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyZWF0ID0gJ2NvbmRpdGlvbl9kdW1teScgLCBjb250cm9sLnZhbHVlID0gMSwgdHJlYXQudmFsdWUgPSAzICwgIG1lZGlhdG9yID0gJ3JlY19tZW1fcG9zX21vb2RfbGFnJywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpbXM9MTAwMDApDQpzdW1tYXJ5KG1lZF9wb3NfcmVjX2RlcCkNCg0KYGBgDQoNCg0KIyMjIFJlbU5BIHstfQ0KYGBge3J9DQpkZl9tZWRhbF9tb2RlcmF0aW9uID0gZGZfbWVkYWxfY2xlYW5fcmVtb3RlICU+JSBmaWx0ZXIoIShpcy5uYShuZWdfbW9vZCkgfCBpcy5uYShyZWNfbWVtX25lZ19tb29kX2xhZykpKSANCg0KIyBtZWQgbW9kZWwNCm1lZF9maXRfaDFfbmVnX3JlYyA8LSBsbWU0OjpsbWVyKHJlY19tZW1fbmVnX21vb2RfbGFnIH4gY29uZGl0aW9uX2R1bW15ICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWdlICsgZ2VuZGVyICsgZWR1Y2F0aW9uICsgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoMSB8c3ViamVjdGNvZGUpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBkZl9tZWRhbF9tb2RlcmF0aW9uKQ0KIyBmdWxsIG1vZGVsDQpvdXRfZml0X2gxX25lZ19yZWMgPC0gbG1lNDo6bG1lcihuZWdfbW9vZCB+IGNvbmRpdGlvbl9kdW1teSArIHJlY19tZW1fbmVnX21vb2RfbGFnICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2UgKyBnZW5kZXIgK2VkdWNhdGlvbiArIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICgxICsgcmVjX21lbV9uZWdfbW9vZF9sYWd8c3ViamVjdGNvZGUpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGRmX21lZGFsX21vZGVyYXRpb24pDQoNCg0KI21lZGlhdGlvbiBhbmFseXNpcyBmb3IgY29udHJvbCBhbmQgcmVtaXR0ZWQNCnN1bW1hcnkobWVkaWF0aW9uOjptZWRpYXRlKG1lZF9maXRfaDFfbmVnX3JlYywgb3V0X2ZpdF9oMV9uZWdfcmVjLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyZWF0ID0gJ2NvbmRpdGlvbl9kdW1teScgLCBtZWRpYXRvciA9ICdyZWNfbWVtX25lZ19tb29kX2xhZycsIGNvbnRyb2wudmFsdWUgPSAxLCB0cmVhdC52YWx1ZSA9IDIgLCAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc2ltcz0xMDAwMCkpDQoNCiNtZWRpYXRpb24gYW5hbHlzaXMgZm9yIGNvbnRyb2wgYW5kIGRlcHJlc3NlZA0Kc3VtbWFyeShtZWRpYXRpb246Om1lZGlhdGUobWVkX2ZpdF9oMV9uZWdfcmVjLCBvdXRfZml0X2gxX25lZ19yZWMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJlYXQgPSAnY29uZGl0aW9uX2R1bW15JyAsICBtZWRpYXRvciA9ICdyZWNfbWVtX25lZ19tb29kX2xhZycsIGNvbnRyb2wudmFsdWUgPSAxLCB0cmVhdC52YWx1ZSA9IDMgLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc2ltcz0xMDAwMCkpDQoNCmBgYA0KDQojIyBNb2RlcmF0ZWQgTWVkaWF0aW9uIHsudGFic2V0fQ0KDQojIyMgUmVtUEEtQ3VyclBBIHstfQ0KYGBge3J9DQoNCmRmX21lZGFsX21vZGVyYXRpb24gPSBkZl9tZWRhbF9jbGVhbl9yZW1vdGUgJT4lIA0KICBmaWx0ZXIoIShpcy5uYShwb3NfbW9vZCkgfCBpcy5uYShyZW1fbWVtX3Bvc19tb29kX2xhZykpKSANCg0KI21lZGlhdGlvbiBmaXJzdA0KbWVkX2ZpdF9oMl9wb3NfcmVtIDwtIGxtZTQ6OmxtZXIocmVtX21lbV9wb3NfbW9vZF9sYWcgfiBjb25kaXRpb25fZHVtbXkgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWdlICsgZ2VuZGVyICsgZWR1Y2F0aW9uICsgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICgxIHxzdWJqZWN0Y29kZSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9ZGZfbWVkYWxfbW9kZXJhdGlvbikNCiMgZnVsbCBtb2RlbA0Kb3V0X2ZpdF9oMl9wb3NfcmVtIDwtbG1lNDo6bG1lcihwb3NfbW9vZCB+IGNvbmRpdGlvbl9kdW1teSArIHJlbV9tZW1fcG9zX21vb2RfbGFnIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICArIGFnZSArIGdlbmRlciArZWR1Y2F0aW9uICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoMSArIHJlbV9tZW1fcG9zX21vb2RfbGFnIHxzdWJqZWN0Y29kZSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE9ZGZfbWVkYWxfbW9kZXJhdGlvbikNCg0KDQojbWVkaWF0aW9uIGFuYWx5c2lzIGZvciBjb250cm9sIGFuZCByZW1pdHRlZA0KbWVkX3Bvc19yZW1fcmVtIDwtIG1lZGlhdGlvbjo6bWVkaWF0ZShtZWRfZml0X2gyX3Bvc19yZW0sIG91dF9maXRfaDJfcG9zX3JlbSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyZWF0ID0gJ2NvbmRpdGlvbl9kdW1teScgLCBjb250cm9sLnZhbHVlID0gMSwgdHJlYXQudmFsdWUgPSAyICwgIG1lZGlhdG9yID0gJ3JlbV9tZW1fcG9zX21vb2RfbGFnJykNCnN1bW1hcnkobWVkX3Bvc19yZW1fcmVtKQ0KDQojY3JlYXRlIG5ldyBkYXRhZnJhbWVzIHdpdGggb25seSBjb250cm9sIHJlbWl0dGVkIGFuZCBvbmx5IGNvbnRyb2wgZGVwcmVzc2VkDQpkZl9tZWRhbF9jb25fcmVtID0gZGZfbWVkYWxfY2xlYW4gJT4lIGZpbHRlcihjb25kaXRpb249PSdjb250cm9sJyB8IGNvbmRpdGlvbiA9PSAncmVtaXR0ZWQnKQ0KZGZfbWVkYWxfY29uX2RlcCA9IGRmX21lZGFsX2NsZWFuICU+JSBmaWx0ZXIoY29uZGl0aW9uPT0nY29udHJvbCcgfCBjb25kaXRpb24gPT0gJ2RlcHJlc3NlZCcpDQoNCiNyZW1pdHRlZCBncm91cA0KZGZfbWVkYWxfY29uX3JlbSRjb25kaXRpb25fZHVtbXkgPSBidWlsZF9jb250cmFzdChkZl9tZWRhbF9jb25fcmVtJGNvbmRpdGlvbiwgJ2NvbnRyb2wnLCAncmVtaXR0ZWQnKQ0KbWVkX2gyX3Bvc19yZW1fcmVtIDwtIG1kdF9tb2RlcmF0ZWQoZGF0YSA9IGRmX21lZGFsX2Nvbl9yZW0sIElWID1jb25kaXRpb25fZHVtbXksIERWID0gcG9zX21vb2QsIE0gPSByZW1fbWVtX3Bvc19tb29kX2xhZywgTW9kID0gcG9zX21vb2RfbGFnX3JlbSkgDQpyYmluZGxpc3QobWVkX2gyX3Bvc19yZW1fcmVtJHBhdGhzLCBpZGNvbCA9IFQpDQoNCmBgYA0KDQojIyMgUmVtTkEgLSBDdXJyTkEgey19DQpgYGB7ciBwYWdlZC5wcmludD1UUlVFfQ0KZGZfbWVkYWxfbW9kZXJhdGlvbiA9IGRmX21lZGFsX2NsZWFuX3JlbW90ZSAlPiUgZmlsdGVyKCEoaXMubmEobmVnX21vb2QpIHwgaXMubmEocmVtX21lbV9uZWdfbW9vZF9sYWcpKSkgDQoNCiNtZWRpYXRpb24gZmlyc3QNCm1lZF9maXRfaDJfbmVnX3JlbSA8LSBsbWU0OjpsbWVyKHJlbV9tZW1fbmVnX21vb2RfbGFnIH4gY29uZGl0aW9uX2R1bW15ICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWdlICsgZ2VuZGVyICsgZWR1Y2F0aW9uICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKDEgfHN1YmplY3Rjb2RlKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyb2wgPSBsbWVyQ29udHJvbChjYWxjLmRlcml2cyA9IEYsIG9wdGltaXplcj0nYm9ieXFhJywgb3B0Q3RybD1saXN0KG1heGZ1bj0xZTYpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPWRmX21lZGFsX21vZGVyYXRpb24pDQoNCm91dF9maXRfaDJfbmVnX3JlbSA8LWxtZTQ6OmxtZXIobmVnX21vb2QgfiBjb25kaXRpb25fZHVtbXkgKyByZW1fbWVtX25lZ19tb29kX2xhZyArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWdlICsgZ2VuZGVyICsgZWR1Y2F0aW9uICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoMSArIHJlbV9tZW1fbmVnX21vb2RfbGFnIHxzdWJqZWN0Y29kZSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cm9sID0gbG1lckNvbnRyb2woY2FsYy5kZXJpdnMgPSBGLCBvcHRpbWl6ZXI9J2JvYnlxYScsIG9wdEN0cmw9bGlzdChtYXhmdW49MWU2KSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE9ZGZfbWVkYWxfbW9kZXJhdGlvbikNCg0KI21lZGlhdGlvbiBhbmFseXNpcyBmb3IgY29udHJvbCBhbmQgZGVwcmVzc2VkDQptZWRfbmVnX3JlbV9kZXAgPC0gbWVkaWF0aW9uOjptZWRpYXRlKG1lZF9maXRfaDJfbmVnX3JlbSwgb3V0X2ZpdF9oMl9uZWdfcmVtLCAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lZGlhdG9yID0gJ3JlbV9tZW1fbmVnX21vb2RfbGFnJywgIHRyZWF0ID0gJ2NvbmRpdGlvbl9kdW1teScgLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJvbC52YWx1ZSA9IDEsIHRyZWF0LnZhbHVlID0gMyAsIHNpbXM9MTAwMDApIA0Kc3VtbWFyeShtZWRfbmVnX3JlbV9kZXApDQoNCiNtZWRpYXRpb24gYW5hbHlzaXMgZm9yIGNvbnRyb2wgYW5kIHJlbWl0dGVkDQptZWRfbmVnX3JlbV9yZW0gPC0gbWVkaWF0aW9uOjptZWRpYXRlKG1lZF9maXRfaDJfbmVnX3JlbSwgb3V0X2ZpdF9oMl9uZWdfcmVtLCB0cmVhdCA9ICdjb25kaXRpb25fZHVtbXknICwgY29udHJvbC52YWx1ZSA9IDEsIHRyZWF0LnZhbHVlID0gMiAsICBtZWRpYXRvciA9ICdyZW1fbWVtX25lZ19tb29kX2xhZycsIHNpbXM9MTAwMDApIA0Kc3VtbWFyeShtZWRfbmVnX3JlbV9yZW0pDQoNCiNjcmVhdGUgbmV3IGRhdGFmcmFtZXMgd2l0aCBvbmx5IGNvbnRyb2wgcmVtaXR0ZWQgYW5kIG9ubHkgY29udHJvbCBkZXByZXNzZWQNCmRmX21lZGFsX2Nvbl9yZW0gPSBkZl9tZWRhbF9jbGVhbiAlPiUgZmlsdGVyKGNvbmRpdGlvbj09J2NvbnRyb2wnIHwgY29uZGl0aW9uID09ICdyZW1pdHRlZCcpDQpkZl9tZWRhbF9jb25fZGVwID0gZGZfbWVkYWxfY2xlYW4gJT4lIGZpbHRlcihjb25kaXRpb249PSdjb250cm9sJyB8IGNvbmRpdGlvbiA9PSAnZGVwcmVzc2VkJykNCg0KI3JlbWl0dGVkIGdyb3VwDQpkZl9tZWRhbF9jb25fcmVtJGNvbmRpdGlvbl9kdW1teSA9IGJ1aWxkX2NvbnRyYXN0KGRmX21lZGFsX2Nvbl9yZW0kY29uZGl0aW9uLCAnY29udHJvbCcsICdyZW1pdHRlZCcpDQptZWRfaDJfbmVnX3JlbV9yZW0gPC0gbWR0X21vZGVyYXRlZChkYXRhID0gZGZfbWVkYWxfY29uX3JlbSwgSVYgPSBjb25kaXRpb25fZHVtbXksIERWID0gbmVnX21vb2QsIE0gPSByZW1fbWVtX25lZ19tb29kX2xhZywgTW9kID0gbmVnX21vb2RfbGFnX3JlbSkgDQpyYmluZGxpc3QobWVkX2gyX25lZ19yZW1fcmVtJHBhdGhzLCBpZGNvbCA9IFQpDQoNCiNkZXByZXNzZWQgZ3JvdXANCmRmX21lZGFsX2Nvbl9kZXAkY29uZGl0aW9uX2R1bW15ID0gYnVpbGRfY29udHJhc3QoZGZfbWVkYWxfY29uX2RlcCRjb25kaXRpb24sICdjb250cm9sJywgJ2RlcHJlc3NlZCcpDQptZWRfaDJfbmVnX3JlbV9kZXAgPC0gbWR0X21vZGVyYXRlZChkYXRhID0gZGZfbWVkYWxfY29uX2RlcCwgSVYgPSBjb25kaXRpb25fZHVtbXksIERWID0gbmVnX21vb2QsIE0gPSByZW1fbWVtX25lZ19tb29kX2xhZywgTW9kID0gbmVnX21vb2RfbGFnX3JlbSkgDQpyYmluZGxpc3QobWVkX2gyX25lZ19yZW1fZGVwJHBhdGhzLGlkY29sID0gVCkNCiAgDQpgYGANCg0KIyMgQ29udGV4dA0KDQpgYGB7cn0NCmFzaXNfb3V0cHV0KHRhYl9tb2RlbCggKGxtZXIocG9zX21vb2RfY3MgfiByZWNfbWVtX3Bvc19tb29kX2NzX2xhZypjb250ZXh0X2xvY2F0aW9uICsgKDEgIHwgc3ViamVjdGNvZGUpLCBkYXRhID0gZGZfbWVkYWxfY2xlYW4pKSwgDQogICAgICAgICAgIChsbWVyKHBvc19tb29kX2NzIH4gcmVtX21lbV9wb3NfbW9vZF9jc19sYWcqY29udGV4dF9sb2NhdGlvbiArICgxICB8IHN1YmplY3Rjb2RlKSwgZGF0YSA9IGRmX21lZGFsX2NsZWFuKSksDQogICAgICAgICAgICAobG1lcihuZWdfbW9vZF9jcyB+IHJlbV9tZW1fbmVnX21vb2RfY3NfbGFnKmNvbnRleHRfbG9jYXRpb24gKyAoMSAgfCBzdWJqZWN0Y29kZSksIGRhdGEgPSBkZl9tZWRhbF9jbGVhbikpLA0KICAgICAgICAgICAgIChsbWVyKG5lZ19tb29kX2NzIH4gcmVtX21lbV9uZWdfbW9vZF9jc19sYWcqY29udGV4dF9sb2NhdGlvbiArICgxICB8IHN1YmplY3Rjb2RlKSwgZGF0YSA9IGRmX21lZGFsX2NsZWFuKSkpJGtuaXRyKQ0KDQpgYGANCg0KIyMgU1JFVA0KDQpJbiBhZGRpdGlvbiB0byB0aGUgRU1BLCBwYXJ0aWNpcGFudHMgYWxzbyBjb21wbGV0ZWQgdGhlIFNSRVQuIFRoaXMgaXMgYSBsYWIgYmFzZWQgbWVtb3J5IGJpYXMgbWVhc3VyZS4gV2Ugd2FudCB0byBjaGVjayB3aGV0aGVyIG91ciBtZW1vcnkgYmlhcyBtZWFzdXJlcyBmcm9tIHJlYWwtbGlmZSBhcmUgbGlua2VkIHRvIG9uZXMgZnJvbSB0aGUgbGFiIGluIHRoaXMgc3VwcGxlbWVudGFyeSBhbmFseXNpcy4gDQoNCmBgYHtyfQ0KDQpsaWJyYXJ5KCdoYXZlbicpDQpzcmV0X2ZpbGUgPSBmaWxlLnBhdGgoIlo6LyIsICJpbmJveCIsICJ0cmFuc2Zlci0yMDIzLTEyLTA3LTAyLTE1LXBtIiwgJ01FREFMX3ByZSBhbmQgcG9zdCBxdWVzdCBhbmQgcmVtb3RlIHJlY2FsbF93b3JrZmlsZSEhX2ZvciBwYXBlciBvbmx5IHZhci5zYXYnKQ0Kc3JldF9kYXRhID0gcmVhZF9zYXYoc3JldF9maWxlKSANCnNyZXRfZGF0YSA9IHNyZXRfZGF0YSAlPiUgc2VsZWN0KGMoMSw0KSkgJT4lIGRpc3RpbmN0KCkNCg0KZGZfbWVkYWxfcmVjX2NvcjEgPSBkZl9tZWRhbF9jbGVhbiAlPiUNCiAgZHBseXI6OnNlbGVjdChzdWJqZWN0Y29kZSwgcG9zX21vb2QsIHJlY19tZW1fcG9zX21vb2RfbGFnKSAlPiUNCiAgbmEub21pdCgpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN1YmplY3Rjb2RlKSAlPiUNCiAgZHBseXI6Om11dGF0ZShjb3JyID0gIHRyeUNhdGNoKGNvcihyZWNfbWVtX3Bvc19tb29kX2xhZywgcG9zX21vb2QpLCB3YXJuaW5nID0gZnVuY3Rpb24oZSkgTkEpLA0KICAgICAgICAgICAgICAgIG1vZGVsX3R5cGUgPSAiUEFfUkVDIikgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHN1YmplY3Rjb2RlLCBjb3JyLCBtb2RlbF90eXBlKSAlPiUgDQogIGRwbHlyOjpkaXN0aW5jdCgpICAlPiUgdW5ncm91cCgpDQoNCg0KZGZfbWVkYWxfcmVjX2NvcjIgPSBkZl9tZWRhbF9jbGVhbiAlPiUNCiAgZHBseXI6OnNlbGVjdChzdWJqZWN0Y29kZSwgbmVnX21vb2QsIHJlY19tZW1fbmVnX21vb2RfbGFnKSAlPiUNCiAgbmEub21pdCgpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN1YmplY3Rjb2RlKSAlPiUNCiAgZHBseXI6Om11dGF0ZShjb3JyID0gIHRyeUNhdGNoKGNvcihyZWNfbWVtX25lZ19tb29kX2xhZywgbmVnX21vb2QpLCB3YXJuaW5nID0gZnVuY3Rpb24oZSkgTkEpLA0KICAgICAgICAgICAgICAgIG1vZGVsX3R5cGUgPSAiTkFfUkVDIikgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHN1YmplY3Rjb2RlLCBjb3JyLCBtb2RlbF90eXBlKSAlPiUgDQogIGRwbHlyOjpkaXN0aW5jdCgpICU+JSB1bmdyb3VwKCkNCg0KDQpkZl9tZWRhbF9yZW1fY29yMSA9IGRmX21lZGFsX2NsZWFuICU+JQ0KICBkcGx5cjo6c2VsZWN0KHN1YmplY3Rjb2RlLCBwb3NfbW9vZCwgcmVtX21lbV9wb3NfbW9vZF9sYWcpICU+JQ0KICBuYS5vbWl0KCkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3ViamVjdGNvZGUpICU+JQ0KICBkcGx5cjo6bXV0YXRlKGNvcnIgPSB0cnlDYXRjaChjb3IocmVtX21lbV9wb3NfbW9vZF9sYWcsIHBvc19tb29kKSwgd2FybmluZyA9IGZ1bmN0aW9uKGUpIE5BKSwNCiAgICAgICAgICAgICAgICBtb2RlbF90eXBlID0gIlBBX1JFTSIpICU+JSANCiAgZHBseXI6OnNlbGVjdChzdWJqZWN0Y29kZSwgY29yciwgbW9kZWxfdHlwZSkgJT4lIA0KICBkcGx5cjo6ZGlzdGluY3QoKQ0KDQpkZl9tZWRhbF9yZW1fY29yMiA9IGRmX21lZGFsX2NsZWFuICU+JQ0KICBkcGx5cjo6c2VsZWN0KHN1YmplY3Rjb2RlLCBuZWdfbW9vZCwgcmVtX21lbV9uZWdfbW9vZF9sYWcpICU+JQ0KICBuYS5vbWl0KCkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3ViamVjdGNvZGUpICU+JQ0KICBkcGx5cjo6bXV0YXRlKGNvcnIgPSB0cnlDYXRjaChjb3IocmVtX21lbV9uZWdfbW9vZF9sYWcsIG5lZ19tb29kKSwgd2FybmluZyA9IGZ1bmN0aW9uKGUpIE5BKSwNCiAgICAgICAgICAgICAgICBtb2RlbF90eXBlID0gIk5BX1JFTSIpICU+JSANCiAgZHBseXI6OnNlbGVjdChzdWJqZWN0Y29kZSwgY29yciwgbW9kZWxfdHlwZSkgJT4lIA0KICBkcGx5cjo6ZGlzdGluY3QoKQ0KDQoNCmRmX2NvcnMgPSByYmluZGxpc3QobGlzdChkZl9tZWRhbF9yZWNfY29yMSwgZGZfbWVkYWxfcmVjX2NvcjIsIGRmX21lZGFsX3JlbV9jb3IxLCBkZl9tZWRhbF9yZW1fY29yMikpDQoNCmRmX3JlZiA9IG1lcmdlKHNyZXRfZGF0YSwgZGZfY29ycywgYnkueCA9ICdzdWJqZWN0JywgYnkueSA9ICdzdWJqZWN0Y29kZScpDQpkZl9yZWYgPSBkZl9yZWYgJT4lIHJlbmFtZShTUkVUID0gU1JFVF9CaWFzR290bGliX25lZykgJT4lIGRwbHlyOjptdXRhdGUoZ3JvdXAgPSBpZmVsc2Uoc3ViamVjdDw4MDAsICJyZW1pdHRlZCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2Uoc3ViamVjdD49OTAwLCAiY29udHJvbCIsICdkZXByZXNzZWQnKSkgKQ0KDQoNCmZvciAobW9kX3R5cGUgaW4gYygiUEFfUkVDIiwgIlBBX1JFTSIsICJOQV9SRUMiLCAiTkFfUkVNIikpew0KICBwcmludChtb2RfdHlwZSkNCiAgcHJpbnQoc3VtbWFyeShsbShTUkVUIH4gY29ycipncm91cCwgZGF0YSA9IGRmX3JlZiAlPiUgZmlsdGVyKG1vZGVsX3R5cGUgPT0gbW9kX3R5cGUpKSkpDQp9DQoNCg0KYGBgDQoNCg0KIyMgUmVsYXRpdmUgQmlhcw0KDQpIZXJlIHdlIHdhbnQgdG8gY2hlY2sgZm9yIHRoZSByZWxhdGl2ZSBOQS9QQSBiaWFzLiBTbyB3ZSBleHRhY3QgdGhlIHJhbmRvbSBlZmZlY3RzIGZyb20gdGhlIG1vZGVscyB0byBnZXQgdGhlIHNsb3BlcyBmb3IgZWFjaCBzdWJqZWN0LCBhbmQgdGhlbiBjb21wYXJlIHRoZSBOQS9QQSBzbG9wZXMuIFRoaXMgdGVsbHMgdXMgaWYgdGhlcmVzIGEgYmlhcyBiZXR3ZWVuIG5lZ2F0aXZlIGFuZCBwb3NpdGl2ZSBtZW1vcnkuDQoNCmBgYHtyfQ0KDQojIEdldCBpbmRpdmlkdWFsIHNsb3Blcw0KcG9zX3JlY19yZWYgPSBhcy5kYXRhLmZyYW1lKHJhbmVmKGgxX3Bvc19yZWNlbnRfbW9kZWxzW1syXV0pKSAlPiUgZmlsdGVyKHRlcm0hPScoSW50ZXJjZXB0KScpICU+JSBzZWxlY3QoYygzOjUpKQ0KcG9zX3JlbV9yZWYgPSBhcy5kYXRhLmZyYW1lKHJhbmVmKGgxX3Bvc19yZW1vdGVfbW9kZWxzW1syXV0pKSAlPiUgZmlsdGVyKHRlcm0hPScoSW50ZXJjZXB0KScpICU+JSBzZWxlY3QoYygzOjUpKQ0KbmVnX3JlY19yZWYgPSBhcy5kYXRhLmZyYW1lKHJhbmVmKGgxX25lZ19yZWNlbnRfbW9kZWxzW1s0XV0pKSAlPiUgZmlsdGVyKHRlcm0hPScoSW50ZXJjZXB0KScpICU+JSBzZWxlY3QoYygzOjUpKQ0KbmVnX3JlbV9yZWYgPSBhcy5kYXRhLmZyYW1lKHJhbmVmKGgxX25lZ19yZW1vdGVfbW9kZWxzW1s0XV0pKSAlPiUgZmlsdGVyKHRlcm0hPScoSW50ZXJjZXB0KScpICU+JSBzZWxlY3QoYygzOjUpKQ0KcG9zX3JlY19yZWYkbW9kID0gIlBBX1JFQyINCnBvc19yZW1fcmVmJG1vZCA9ICJQQV9SRU0iDQpuZWdfcmVjX3JlZiRtb2QgPSAiTkFfUkVDIg0KbmVnX3JlbV9yZWYkbW9kID0gIk5BX1JFTSINCg0KIyBQdXQgdG9nZXRoZXIgaW50byBhIG5ldyBkYXRhIGZyYW1lDQpkZl9yZWYgPSByYmluZGxpc3QobGlzdChwb3NfcmVjX3JlZiwgcG9zX3JlbV9yZWYsIG5lZ19yZWNfcmVmLCBuZWdfcmVtX3JlZikpDQpkZl9yZWYgPSBkZl9yZWYgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHN1YiA9IGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGdycCkpKSAlPiUNCiAgZHBseXI6Om11dGF0ZShncm91cCA9IGlmZWxzZShzdWIgPD0gODAwLCAicmVtaXR0ZWQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2Uoc3ViPj05MDAsICJjb250cm9sIiwgJ2RlcHJlc3NlZCcpKSApDQoNCmRmX3JlZl9yZWMgPSBkZl9yZWYgJT4lIGZpbHRlcihtb2QgPT0gJ1BBX1JFQycgfCBtb2Q9PSdOQV9SRUMnKQ0KZGZfcmVmX3JlbSA9IGRmX3JlZiAlPiUgZmlsdGVyKG1vZCA9PSAnUEFfUkVNJyB8IG1vZD09J05BX1JFTScpDQpzdW1tYXJ5KGxtZXIoY29uZHNkIH4gbW9kKmdyb3VwICsgKDF8c3ViKSwgZGF0YSA9IGRmX3JlZl9yZWMpKQ0Kc3VtbWFyeShsbWVyKGNvbmRzZCB+IG1vZCpncm91cCArICgxfHN1YiksIGRhdGEgPSBkZl9yZWZfcmVtKSkNCmBgYA0KDQoNCg0KIyBQbG90cw0KDQpGaXJzdCB3ZSBzZXQgb3VyIHRoZW1lIGFuZCBmaXggdGhlIGRhdGEgZm9yIHRoZSBmaWd1cmVzIHdlIHdhbnQNCmBgYHtyfQ0KIyBUaGVtZQ0KZ2d0aGVtZSA9IHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLCANCiAgICAgICAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwgDQogICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJncmV5OTAiKSwNCiAgICAgICAgICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9saW5lKGNvbG9yID0gImdyZXkxMDAiKSwNCiAgICAgICAgICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3IgPSAiZ3JleTgwIiwgZmlsbCA9ICJ0cmFuc3BhcmVudCIpKQ0KDQojIEVzdGltYXRlIHRoZSBTRA0KZGZfbWVkYWxfY2xlYW4yID0gZGZfbWVkYWxfY2xlYW4gJT4lIA0KICBtdXRhdGUocG9zX21vb2Rfc2QgPSBpZmVsc2UoIChwb3NfbW9vZF9jc19sYWdfcmVjID4gKG1lYW4ocG9zX21vb2RfY3NfbGFnX3JlYywgbmEucm09VCkrc2QocG9zX21vb2RfY3NfbGFnX3JlYywgbmEucm09VCkpKSwgIisxU0QiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZSggKHBvc19tb29kX2NzX2xhZ19yZWMgPCAobWVhbihwb3NfbW9vZF9jc19sYWdfcmVjLCBuYS5ybT1UKS1zZChwb3NfbW9vZF9jc19sYWdfcmVjLCBuYS5ybSA9VCkpKSwgIi0xU0QiLCAiTWVhbiIpKSkgJT4lIA0KICAgIG11dGF0ZShuZWdfbW9vZF9zZCA9IGlmZWxzZSggKG5lZ19tb29kX2NzX2xhZ19yZWMgPiAobWVhbihuZWdfbW9vZF9jc19sYWdfcmVjLCBuYS5ybT1UKStzZChuZWdfbW9vZF9jc19sYWdfcmVjLCBuYS5ybT1UKSkpLCAiKzFTRCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKCAobmVnX21vb2RfY3NfbGFnX3JlYyA8IChtZWFuKG5lZ19tb29kX2NzX2xhZ19yZWMsIG5hLnJtPVQpLXNkKG5lZ19tb29kX2NzX2xhZ19yZWMsIG5hLnJtID1UKSkpLCAiLTFTRCIsICJNZWFuIikpKQ0KDQojIEZpeCBmYWN0b3IgbGV2ZWxzDQpkZl9tZWRhbF9jbGVhbjIkQ29uZGl0aW9uID0gIGZhY3RvcihkZl9tZWRhbF9jbGVhbjIkY29uZGl0aW9uLCBsZXZlbHM9YygnY29udHJvbCcsICdyZW1pdHRlZCcsICdkZXByZXNzZWQnICksIGxhYmVscz1jKCdOZXZlci1EZXByZXNzZWQnLCAnUmVtaXR0ZWQnLCAnRGVwcmVzc2VkJykpDQpkZl9tZWRhbF9jbGVhbjIkcG9zX21vb2Rfc2QgPSAgZmFjdG9yKGRmX21lZGFsX2NsZWFuMiRwb3NfbW9vZF9zZCwgbGV2ZWxzPWMoJy0xU0QnLCAnTWVhbicsICcrMVNEJyApKQ0KZGZfbWVkYWxfY2xlYW4yJG5lZ19tb29kX3NkID0gIGZhY3RvcihkZl9tZWRhbF9jbGVhbjIkbmVnX21vb2Rfc2QsIGxldmVscz1jKCctMVNEJywgJ01lYW4nLCAnKzFTRCcgKSkNCg0KDQpgYGANCg0KIyMjIFBBLUNVUi1SRUMNCmBgYHtyfQ0KDQojIFBsb3QNCnBsb3RfcGFfcmVjID0gZ2dwbG90KGRmX21lZGFsX2NsZWFuMiwgYWVzKHggPSByZWNfbWVtX3Bvc19tb29kX2NfbGFnLCB5PXBvc19tb29kX2MsIGNvbG9yID0gcG9zX21vb2Rfc2QsIGZpbGwgPSBwb3NfbW9vZF9zZCkpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gJ2xtJywgYWxwaGEgPSAwLjE1KSArDQogIGxhYnMoIHggPSBicXVvdGUocGFzdGUoUkVDW1BNXSwgIiAoc3ViamVjdC1jZW50ZXJlZCBhLnUuKSIpKSwgeSA9ICJQTSAoc3ViamVjdC1jZW50ZXJlZCBhLnUuKSIsIGNvbG9yID0gYnF1b3RlKENVUltQTV0pLCBmaWxsID0gYnF1b3RlKENVUltQTV0pICkgKw0KICBnZ3RoZW1lICsgDQogIGZhY2V0X2dyaWQoLn5Db25kaXRpb24pIA0KcGxvdF9wYV9yZWMNCmBgYA0KDQojIyMgUEEtQ1VSLVJFQw0KDQpgYGB7cn0NCg0KIyBQbG90DQpwbG90X25hX3JlYyA9IA0KICBnZ3Bsb3QoZGZfbWVkYWxfY2xlYW4yLCBhZXMoeCA9IHJlY19tZW1fbmVnX21vb2RfY19sYWcsIHk9bmVnX21vb2RfYywgY29sb3IgPSBuZWdfbW9vZF9zZCwgZmlsbCA9IG5lZ19tb29kX3NkKSkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAnbG0nLCBhbHBoYSA9IDAuMTUpICsNCiAgbGFicyggeCA9IGJxdW90ZShwYXN0ZShSRUNbJ05NJ10sICIgKHN1YmplY3QtY2VudGVyZWQgYS51LikiKSksIHkgPSAiTk0gKHN1YmplY3QtY2VudGVyZWQgYS51LikiLCBjb2xvciA9IGJxdW90ZShDVVJbIk5NIl0pLCBmaWxsID0gYnF1b3RlKENVUlsiTk0iXSkgKSsNCiAgZ2d0aGVtZSArIA0KICBmYWNldF9ncmlkKC5+Q29uZGl0aW9uKSANCnBsb3RfbmFfcmVjDQpgYGANCg0KIyMjIENvbWJpbmVkIFBsb3QgZm9yIHB1Yg0KYGBge3J9DQpnZ2FycmFuZ2UoTkEsIHBsb3RfcGFfcmVjLCBOQSwgIHBsb3RfbmFfcmVjLA0KICAgICAgICAgIHdpZHRocz1jKDAuMDUsIDEsIDAuMDUsIDEpLCBuY29sID0gMiwgbnJvdyA9IDIsDQogICAgICAgICAgbGFiZWxzPWMoIkEiLCBOQSwgIkIiKSkNCmdnc2F2ZSgiZmlndXJlcy9maWd1cmVfMl90aHJlZXdheUludGVyYWN0aW9uLnBkZiIsIGRldmljZSA9ICdwZGYnLCBkcGkgPSAzMjAsIGhlaWdodCA9IDYpDQoNCmBgYA0KDQoNCg0KDQoNCg0K